我有一个住院数据集('法术') - 每个法术1行。我想放弃一周之内记录的任何咒语(可能有多个) - 理由是它们可能是同一根本原因的症状。这是一些游戏数据:
create table hif_user.rzb_recurse_src (
patid integer not null,
eventdate integer not null,
type smallint not null
);
insert into hif_user.rzb_recurse_src values (1,1,1);
insert into hif_user.rzb_recurse_src values (1,3,2);
insert into hif_user.rzb_recurse_src values (1,5,2);
insert into hif_user.rzb_recurse_src values (1,9,2);
insert into hif_user.rzb_recurse_src values (1,14,2);
insert into hif_user.rzb_recurse_src values (2,1,1);
insert into hif_user.rzb_recurse_src values (2,5,1);
insert into hif_user.rzb_recurse_src values (2,19,2);
只有类型2的法术 - 在任何其他法术后一周内 - 才会被删除。类型1法术将保留。
对于患者1,日期1&应该保留9。对于患者2,所有行都应保留。
问题在于患者1.法术日期9被确定为在接近法术日期5时掉落;但是,由于法术日期5接近法术日期1应该被删除因此允许法术日期9生效...
所以,这似乎是一个递归问题。但是,我之前没有在SQL中使用递归编程,而且我很难真正想象如何去做。有人可以帮忙吗?我应该补充一点,我正在使用Teradata,它比递归SQL具有更多限制(只允许使用UNION ALL集)。
答案 0 :(得分:0)
我认为解决这个问题的关键是从当前日期开始超过7天的第一个日期,然后再做一个递归子查询:
with rrs as (
select rrs.*,
(select min(rrs2.eventdate)
from hif_user.rzb_recurse_src rrs2
where rrs2.patid = rrs.patid and
rrs2.eventdate > rrs.eventdate + 7
) as eventdate7
from hif_user.rzb_recurse_src rrs
),
recursive cte as (
select patid, min(eventdate) as eventdate, min(eventdate7) as eventdate7
from hif_user.rzb_recurse_src rrs
group by patid
union all
select cte.patid, cte.eventdate7, rrs.eventdate7
from cte join
hif_user.rzb_recurse_src rrs
on rrs.patid = cte.patid and
rrs.eventdate = cte.eventdate7
)
select cte.patid, cte.eventdate
from cte;
如果您想要其他列,请在最后一步加入原始表。
答案 1 :(得分:0)
它是一个游标逻辑,如果它符合你的规则,则检查一行接一行,因此递归是解决问题的最简单(也许是唯一的)方法。
为了获得不错的性能,您需要一个易失性表来促进这种逐行处理:
CREATE VOLATILE TABLE vt (patid, eventdate, exac_type, rn, startdate) AS
(
SELECT r.*
,ROW_NUMBER() -- needed to facilitate the join
OVER (PARTITION BY patid ORDER BY eventdate) AS rn
FROM hif_user.rzb_recurse_src AS r
) WITH DATA ON COMMIT PRESERVE ROWS;
WITH RECURSIVE cte (patid, eventdate, exac_type, rn, startdate) AS
(
SELECT vt.*
,eventdate AS startdate
FROM vt
WHERE rn = 1 -- start with the first row
UNION ALL
SELECT vt.*
-- check if type = 1 or more than 7 days from the last eventdate
,CASE WHEN vt.eventdate > cte.startdate + 7
OR vt.exac_type = 1
THEN vt.eventdate -- new start date
ELSE cte.startdate -- keep old date
END
FROM vt JOIN cte
ON vt.patid = cte.patid
AND vt.rn = cte.rn + 1 -- proceed to next row
)
SELECT *
FROM cte
WHERE eventdate - startdate = 0 -- only new start days
order by patid, eventdate