删除在移动时间窗口内标识的行

时间:2014-07-29 12:59:56

标签: sql teradata recursive-query

我有一个住院数据集('法术') - 每个法术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集)。

2 个答案:

答案 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