2016-09-12 16 views
3

私はSQLをかなり新しくしており、訪問日に基づいて患者にポイントを割り当てることに問題があります。私は再帰的なCTEがこれを達成するための最良の方法だと思っていますが、私は実際にそれを書いて周りに頭を包むことはできません。SQL:グループ化された日付範囲による再帰的CTE

各OrganizationMrnには、過去3日間に別の訪問があった場合を除いて1回の訪問ごとに1ポイントを割り当てる必要があります。患者が3日間で複数回訪問した場合は、1つのポイントを割り当てる必要があります。

説明されているようにポイントを割り当てる再帰的なcteへの私のクエリの変更は、非常に感謝しています。

例:患者は、これらの7回の訪問を有する
:1/1、1/2、1/3 1/4、1/5、1/6、1/11。この患者には、1点(1/1-1/4)、1点(1/5-1/6)、1点(1/11)の3点を割り当てる必要があります。

クエリの説明: 患者25の合計ポイントは5です。
日付範囲2015-10-02 - 2015-10-05に1ポイントを割り当てる必要があります。
日付範囲2015-11-08 - 2015-11-09に1ポイントを割り当てる必要があります。
他の日付は3日以内に別の日付を持たないため、1ポイントを割り当てる必要があります。

WITH CTE AS 
    (
    SELECT 
    ROW_NUMBER() OVER (PARTITION BY OrganizationMrn ORDER BY [Date]) AS ROWNUMBER, * 
    FROM #RC 
    ) 
    SELECT *, 
    ISNULL(DATEDIFF(DY,(SELECT OTHER.[Date] FROM CTE OTHER WHERE OTHER.OrganizationMrn = CTE.OrganizationMrn AND OTHER.ROWNUMBER = CTE.ROWNUMBER - 1), CTE.[Date]),0) AS DaysFromLastVisit, 
    CASE WHEN ISNULL(DATEDIFF(DY,(SELECT OTHER.[Date] FROM CTE OTHER WHERE OTHER.OrganizationMrn = CTE.OrganizationMrn AND OTHER.ROWNUMBER = CTE.ROWNUMBER - 1), CTE.[Date]),0) > 3 THEN 1 END AS POINTS 
    FROM CTE 
    ORDER BY OrganizationMrn, [Date]; 

    ROWNUMBER OrganizationMrn Date  DaysFromLastVisit POINTS 
    1   25    2015-10-02 0     NULL 
    2   25    2015-10-03 1     NULL 
    3   25    2015-10-05 2     NULL 
    4   25    2015-11-08 34     1 
    5   25    2015-11-09 1     NULL 
    6   25    2016-03-04 116     1 
    7   25    2016-05-04 61     1 
    8   25    2016-05-10 6     1 

これは#RCが移入されている方法です。

SELECT I.OrganizationMrn, CAST(R.DTTM AS DATE) AS Date 
INTO #RC 
FROM Standard SD 
    INNER JOIN Iorg I ON I.Person = SD.Patient 
    INNER JOIN Result R ON I.Person = R.Patient 
WHERE 
    R.Entry = 'note' 
AND R.DTTM >= DATEADD(M,-12,GETDATE()) 
AND OrganizationMrn = '25' 
ORDER BY I.OrganizationMrn; 

OrganizationMrn Date 
25    2015-10-02 
25    2015-10-03 
25    2015-10-05 
25    2015-11-08 
25    2015-11-09 
25    2016-03-04 
25    2016-05-04 
25    2016-05-10 

どのように私は3つの日付ののいずれかにポイントを割り当てるには、このCASEステートメントを変更することができますか?現在、毎日10/2、10/3、10/5にポイントが割り当てられています。

CASE 
WHEN ISNULL(DATEDIFF(DY,(SELECT OTHER.[Date] FROM CTE OTHER WHERE OTHER.OrganizationMrn = CTE.OrganizationMrn AND OTHER.ROWNUMBER = CTE.ROWNUMBER - 1), CTE.[Date]),0) <= 3 
THEN 1 ELSE 0 END AS POINTS 
+2

をあなたが入力テーブルを提供することができますそのテーブルの構造とサンプルデータ? –

+1

ここには、再帰CTEではなく、ウィンドウ機能を持つ標準CTEがあります。私が問題を正しく理解しているなら、あなたは本当に再帰的なCTEを必要としません。あなたの日付制限を検証するために参加することができる簡単なサブクエリが必要です –

+0

再帰的なCTEは必要ない場合は必要ありません。再帰的なCTEは、日をグループ化して次のセットに移動する最善の方法だと思いました。お互いの3日間で行をグループ化する方法についてのヒントは、次のセットに移動しますか? – JBritton

答えて

1

個々のグループを出力する必要がありますか、ポイントの値を知るのに十分ですか?後者の場合、これを「ギャップとアイランド」の問題のバリエーションと考えることができます。あなたが深いダイビングをしたい場合は、優れた記事hereがあります。私はそのページのコードスニペットをここに適用しています。

開始ポイントを、その3日以内にレコードを持たないレコードとして定義します。エンドポイントは、3日以内にレコードを持たないレコードです。各島が特定されると、開始点と終了点の間の日数を取って、回答を分割して四捨五入することで、3日間のグループの数を決定することができます。注:以下のコードは、組織1

CREATE TABLE #t(
    OrganizationMrn int, 
    VisitDate date) 

INSERT #t(OrganizationMrn, VisitDate) VALUES 
    (1, '1/1/2016'), 
    (1, '1/2/2016'), 
    (1, '1/3/2016'), 
    (1, '1/4/2016'), 
    (1, '1/5/2016'), 
    (1, '1/6/2016'), 
    (1, '1/11/2016') 

;WITH StartingPoints AS (
    SELECT VisitDate, ROW_NUMBER() OVER (ORDER BY VisitDate) AS Sequence FROM #t AS A 
    WHERE A.OrganizationMrn = 1 AND NOT EXISTS (
     SELECT * FROM #t AS B 
     WHERE B.OrganizationMrn = A.OrganizationMrn AND 
      B.VisitDate >= DATEADD(day, -4, A.VisitDate) 
      AND 
      B.VisitDate < A.VisitDate 
     ) 
), 
EndingPoints AS (
    SELECT VisitDate, ROW_NUMBER() OVER (ORDER BY VisitDate) AS Sequence FROM #t AS A 
    WHERE A.OrganizationMrn = 1 AND NOT EXISTS (
     SELECT * FROM #t AS B 
     WHERE B.OrganizationMrn = A.OrganizationMrn AND 
      B.VisitDate <= DATEADD(day, 4, A.VisitDate) 
      AND 
      B.VisitDate > A.VisitDate 
     ) 
) 

SELECT 
    S.VisitDate AS StartDate 
    ,E.VisitDate AS EndDate 
    ,CEILING((DATEDIFF(day, S.VisitDate, E.VisitDate) + 1)/4.0) AS Points 
FROM 
    StartingPoints AS S 
    JOIN EndingPoints AS E ON (E.Sequence = S.Sequence) 
+0

ありがとうdazedandconfused、私はその仕事だと思います!私はこれを理解しようとすると、あまりにも長く過ごしました。 – JBritton

1

わかりやすい論理lag()窓関数を使用して、現在の行に最初の前の日付を取得して出力条件sum()でポイントを割り当てるか否かをもとにしてハードコードされています。

イベントへの&過去の日付がない場合、以前の日付が日付の間と3日間の後ろか落ちないときのポイントを割り当てます。

select 
    organizationmrn, 
    sum(case when 
     prev_date not between dateadd(day, -3, date) and date 
     or prev_date is null 
     then 1 else 0 end) as points 
from (
    select 
    *, 
    lag(date,1) over (partition by organizationmrn order by date) as prev_date 
    from rc 
) calculate_prev_date 
group by organizationmrn 

結果

organizationmrn | points 
-----------------+-------- 
       25 |  5 
+0

よかった、助けてくれてありがとう! – JBritton

関連する問題