2016-01-22 50 views
0

我有一個患者表,其中一些患者有一個或多個「事件」(基本上是日期)。我需要這些日期加工成使用以下步驟情節: -按照逐步算法將日期處理爲'episodes'

  1. 以下內容的事件,項目遠期14天,作爲一個潛在的結束日期插曲使用。
    a。這段時間內的事件被忽略,被認爲與最初的事件有關。

  2. 如果在潛在的結束日期後的14天內沒有事件發生, 停止算法 - 該事件已被完全識別。

  3. 如果在潛在的結束日期日期後的14天內發生事件, 會將潛在的結束日期日期移至新的事件日期+14天。

  4. 從第2步開始重複,直到從事件結束日期起14天內清除事件。

下面是一些測試數據。 '真正'的數據是patid(患者標識符),eventdate和rn(一個唯一的行號,每個患者重置爲1,按日期順序應用)。 Exp_end是我自己的條目,用於指示劇集的結束日期。這是該行,將是爲情節的最後一個事件: -

"patid","rn", "eventdate", "exp_end" 
    1, 1, 01-01-2010, 14-01-2010 
    1, 2, 11-02-2010, 24-02-2010 
    2, 1, 01-01-2010, 
    2, 2, 07-01-2010, 
    2, 3, 12-01-2010, 14-01-2010 
    2, 4, 21-02-2010, 06-03-2010 
    3, 1, 01-01-2010, 
    3, 2, 12-01-2010, 
    3, 3, 24-01-2010, 06-02-2010 
    3, 4, 21-02-2010, 06-03-2010 
    4, 1, 01-01-2010, 
    4, 2, 24-01-2010, 
    4, 3, 28-01-2010, 
    4, 4, 04-02-2010, 17-02-2010 
    4, 5, 21-02-2010, 06-03-2010 
    5, 1, 26-02-2004, 10-03-2004 
    5, 2, 03-09-2004, 
    5, 3, 09-09-2004, 
    5, 4, 21-09-2004, 04-10-2004 
    5, 5, 05-10-2004, 
    5, 6, 14-10-2004, 
    5, 7, 28-10-2004, 10-11-2004 

的SQL代碼產生相同的表: -

CREATE TABLE dp.ep(eventdate DATE FORMAT 'YY/MM/DD', exp_end DATE FORMAT 'YY/MM/DD', patid INTEGER, rn INTEGER) PRIMARY INDEX pats (patid); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-01-01','YYYY-MM-DD'), NULL, 2.0, 1.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-02-04','YYYY-MM-DD'), TO_DATE('2010-02-17','YYYY-MM-DD'), 4.0, 4.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-01-12','YYYY-MM-DD'), TO_DATE('2010-01-14','YYYY-MM-DD'), 2.0, 3.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-02-21','YYYY-MM-DD'), TO_DATE('2010-03-06','YYYY-MM-DD'), 3.0, 4.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-01-24','YYYY-MM-DD'), TO_DATE('2010-02-06','YYYY-MM-DD'), 3.0, 3.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-01-24','YYYY-MM-DD'), NULL, 4.0, 2.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-01-01','YYYY-MM-DD'), NULL, 3.0, 1.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-02-11','YYYY-MM-DD'), TO_DATE('2010-02-24','YYYY-MM-DD'), 1.0, 2.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-02-21','YYYY-MM-DD'), TO_DATE('2010-03-06','YYYY-MM-DD'), 4.0, 5.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-01-07','YYYY-MM-DD'), NULL, 2.0, 2.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-01-01','YYYY-MM-DD'), NULL, 4.0, 1.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-01-12','YYYY-MM-DD'), NULL, 3.0, 2.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-01-28','YYYY-MM-DD'), NULL, 4.0, 3.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-02-21','YYYY-MM-DD'), TO_DATE('2010-03-06','YYYY-MM-DD'), 2.0, 4.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2010-01-01','YYYY-MM-DD'), TO_DATE('2010-01-14','YYYY-MM-DD'), 1.0, 1.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2004-02-26','YYYY-MM-DD'), TO_DATE('2004-03-10','YYYY-MM-DD'), 5.0, 1.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2004-09-03','YYYY-MM-DD'), NULL, 5.0, 2.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2004-09-09','YYYY-MM-DD'), NULL, 5.0, 3.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2004-09-21','YYYY-MM-DD'), TO_DATE('2004-10-04','YYYY-MM-DD'), 5.0, 4.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2004-10-05','YYYY-MM-DD'), NULL, 5.0, 5.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2004-10-14','YYYY-MM-DD'), NULL, 5.0, 6.0); 
INSERT INTO db.ep (eventdate, exp_end, patid, rn) VALUES(TO_DATE('2004-10-28','YYYY-MM-DD'), TO_DATE('2004-11-10','YYYY-MM-DD'), 5.0, 7.0); 

綜上所述,這些是我希望的結果: -

patid epi_start  epi_end  epi_num 

    1  01JAN2010  14JAN2010   1 
     11FEB2010  24FEB2010   2 


    2  01JAN2010  14JAN2010   1 
     21FEB2010  06MAR2010   2 


    3  01JAN2010  06FEB2010   1 
     21FEB2010  06MAR2010   2 


    4  01JAN2010  17FEB2010   1 
     21FEB2010  06MAR2010   2 

    5  26FEB2004  10MAR2004   1 
     03SEP2004  04OCT2004   2 
     05OCT2004  10NOV2004   3 

(當然,幫助我需要的是上面讓表 - 我可以進一步處理來獲得這種類型的輸出。)

我可以很容易地在SAS中獲得結果,但使用SQL,我正在將我的頭髮撕掉!我想它需要遞歸CTE SQL,我並不擅長...

我使用的是Teradata SQL。

任何幫助將是偉大的。

+0

不完全。如果在第14-28天有事件發生,我需要將情節的潛在結束日期移至該事件(+ 14天)。然後,如果在那段時間還有其他事件發生,我需要包括這一點,再加上14天,等等...... – rambles

+0

'4,2,24-01-2010,'與您的描述不符,應該是' 4,2,14-01-2010,'? – dnoeth

+0

@dnoeth 24-01-2010行似乎沒問題。在01-01-2010之後14-28天,這意味着新的結束日期現在是24-01-2010 +天。然而,28-01有一個事件 - 另一個在04-02 - 將事件結束日期推到04-02 + 14天(= 17-02-2010) – rambles

回答

1

如果我理解正確的規則可以表述爲以下內容:初始事件後

  1. 4個星期內的所有行(RN = 1)屬於首發。

  2. 4周後,只有當前行與前一行之間的差距大於2周時纔開始新的情節。

現在它不再是一個迭代算法。當然,這可以使用遞歸CTE來完成,但我更喜歡窗聚集:-)

這似乎返回正確的結果:

SELECT patid, 
    MIN(eventdate) AS epi_start, 
    CASE 
     WHEN MAX(eventdate) > MIN(eventdate) + 13 -- more than two weeks since start 
     THEN MAX(eventdate) + 13 -- adjust end to two weeks after latest date 
     ELSE MIN(eventdate) + 13 -- two weeks after start 
    END AS epi_end, 
    epi_num 
FROM 
(
    SELECT dt.*, 
     SUM(new_epi) -- calculate the episode number 
     OVER (PARTITION BY patid 
      ORDER BY rn 
      ROWS UNBOUNDED PRECEDING) + 1 AS epi_num 
    FROM 
    (
     SELECT ep.*, 
        -- less than 4 weeks after the initial date 
     CASE WHEN eventdate < MIN(eventdate) OVER (PARTITION BY patid) + 28 
        -- less than 2 weeks after the previous date 
       OR eventdate < MAX(eventdate) -- previous date (equivalent to LAG(eventdate) 
           OVER (PARTITION BY patid 
             ORDER BY rn 
             ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) + 14 
       THEN 0 -- same episode 
       ELSE 1 -- new episode starts 
     END AS new_epi  
     FROM ep 
    ) AS dt 
) AS dt 
GROUP BY patid, epi_num 
ORDER BY 1,4 

如果rnROW_NUMBER你可能擺脫創建該計算使用ORDER BY eventdate代替rn(如果它的每patid唯一的)

編輯:

我沒有正確地得到你的邏輯,它不是b e簡化了,所以不能用OLAP完成,你需要一個遞歸的方法:

WITH RECURSIVE cte 
(
    patid, 
    epi_start, 
    epi_end, 
    potential_end, 
    rn, 
    epi_num 
) 
AS 
(
    SELECT patid, 
     eventdate AS epi_start, 
     eventdate + 13 AS epi_end, 
     eventdate + 13 + 14 AS potential_end, 
     rn, 
     CAST(1 AS SMALLINT) AS epi_num 
    FROM ep 
    WHERE rn = 1 

    UNION ALL 

    SELECT 
     cte.patid, 
     CASE WHEN ep.eventdate <= cte.epi_start + 13 
      THEN cte.epi_start 
      WHEN ep.eventdate <= cte.potential_end 
      THEN cte.epi_start 
      ELSE ep.eventdate 
     END AS epi_start_new, 

     CASE WHEN ep.eventdate <= cte.epi_start + 13 
      THEN cte.epi_end 
      ELSE ep.eventdate + 13 
     END AS epi_end_new, 

     CASE WHEN ep.eventdate <= cte.epi_start + 13 
      THEN cte.potential_end 
      WHEN ep.eventdate <= cte.potential_end 
      THEN ep.eventdate+ 13  
      ELSE ep.eventdate + 13 + 14 
     END AS potential_end_new, 
     ep.rn, 
     epi_num + 
     CASE WHEN epi_start_new <> cte.epi_start THEN 1 ELSE 0 END 
    FROM cte JOIN ep 
    ON cte.patid = ep.patid 
    AND cte.rn +1 = ep.rn 
) 
SELECT patid, MIN(epi_start), MAX(epi_end), epi_num 
FROM cte 
GROUP BY patid, epi_num 
ORDER BY 1,2 
+0

哇,這太棒了。我決不會自己提出這個問題。事實上,它是如此之好,它突出了我的SAS版本的問題......(日期相遇,諸如此類)。非常感謝! – rambles

+0

啊,我說得太快了!我已經添加了另一個例子(patid:5),SQL不太適合。 SQL在10月份產生2集:5Oct到18Oct&28Oct到10Nov。它應該是1集 - 5Oct到10Nov - 因爲28Oct在從5Oct的14-28天窗口中(上面的步驟3)。問題在於分類情節的最裏面的sql語句。對於沒有這種類型的例子事先抱歉。我會看看並更新代碼,如果我能解決它。 – rambles