2

私は患者テーブルを持っています:

PatientId   Admitted
---------   ---------------
1           d/m/yy hh:mm:ss
2           d/m/yy hh:mm:ss
3           d/m/yy hh:mm:ss

私はPatientMeasurementテーブルを持っています(0から多数):

PatientId   MeasurementId   Recorded            Value
---------   -------------   ---------------     -----
1           A               d/h/yy hh:mm:ss     100
1           A               d/h/yy hh:mm:ss     200
1           A               d/h/yy hh:mm:ss     300
2           A               d/h/yy hh:mm:ss     10
2           A               d/h/yy hh:mm:ss     20
1           B               d/h/yy hh:mm:ss     1
1           B               d/h/yy hh:mm:ss     2

次のような結果セットを作成しようとしています。

PatientId   Numerator   Denominator
---------   --------    -----------
1           1           1
2           1           1
3           0           1       

基本的に、測定 A の値が少なくとも 1 つ、測定 B の値が 1 つある場合、患者の分子は 1 になります。この例では、患者 1 には 3 つの A 測定値と 2 つの B 測定値があるため、分子は 1 です。 2 には 2 つの A 測定値がありますが、B 測定値がないため、分子は 0 です。患者には A 測定値も B 測定値もないため、分子は 0 です。

これまでの私のクエリは次のとおりです。

SELECT  PatientId, CASE WHEN a.cnt+b.cnt>2 THEN 1 ELSE 0 END Numerator, 1 Denominator
FROM    patient p

LEFT OUTER JOIN (
    SELECT  PatientId, count(*) cnt
    FROM    PatientMeasurement pm
    WHERE   MeasurementId='A'
    --AND   Recorded <= dateadd(hh, 12, Admitted)
    GROUP BY PatientId
) a ON p.PatientId=a.PatientId

LEFT OUTER JOIN (
    SELECT  PatientId, count(*) cnt
    FROM    PatientMeasurement pm
    WHERE   MeasurementId='B'
    --AND   Recorded <= dateadd(hh, 12, Admitted)
    GROUP BY PatientId
) b ON p.PatientId=b.PatientId

これは、相関する日付制限 (Recorded < dateadd(hh, 12, Admitted) を含めない限り、期待どおりに機能します。残念ながら、この方法で「インライン ビュー」を相関させることは、構文的に有効ではありません。

これにより、SQLを次のように書き直す必要がありました。

SELECT  PatientId, CASE WHEN v.a+v.b>2 THEN 1 ELSE 0 END Numerator, 1 Denominator
FROM    (

    SELECT  PatientId,
    (
        SELECT  PatientId, count(*) cnt
        FROM    PatientMeasurement pm
        WHERE   PatientId=p.PatientId
        AND MeasurementId='A'
        AND Recorded <= dateadd(hh, 12, Admitted)
        GROUP BY PatientId
    ) a,
    (
        SELECT  PatientId, count(*) cnt
        FROM    PatientMeasurement pm
        WHERE   PatientId=p.PatientId
        AND MeasurementId='B'
        AND Recorded <= dateadd(hh, 12, Admitted)
        GROUP BY PatientId
    ) b
    FROM    Patient p
) v

私の質問:これを行うためのより良い、より効率的な方法はありますか?

御時間ありがとうございます。

4

5 に答える 5

1

これを試して :

WITH GroupPatients AS 
    (SELECT MeasurementID, PatientId, Count(*) AS cnt
    FROM PatientMeasurement AS pm
    INNER JOIN Patient p ON pm.PatientID = p.PatientID
    WHERE
        MeasurementId IN ('A', 'B')
    AND
        Recorded <= dateadd(hh, 12, Admitted)
    GROUP BY MeasureMentID, PatientId)

SELECT p.PatientID, Case
    When IsNull(GPA.cnt, 0) > 0 AND IsNull(GPB.cnt, 0) > 0 Then 1
    Else 0
End AS Numerator, 1 AS Denominator
FROM Patient p
LEFT JOIN GroupPatientsA AS GPA ON p.PatientID = GPA.PatientID AND GPA.MeasurementID = 'A'
LEFT JOIN GroupPatientsB AS GPB ON p.PatientID = GPB.PatientID AND GPB.MeasurementID = 'B'

ビジネスロジックにも1つの微調整を加えました-仕様では、患者がAとBの両方の測定値を持っている場合、分子は1である必要があると書かれています-ただし、 a.cnt+b.cnt>2 の句は、いずれかの場合に誤って1を返します.cnt または b.cnt が 3 以上で、その他が 0 です。

于 2009-11-13T16:41:54.053 に答える
1
SELECT  p.*, 
        CASE WHEN
        EXISTS
        (
        SELECT  NULL
        FROM    PatientMeasurement pm
        WHERE   pm.PatientID = p.ID
                AND pm.Type = 'A'
                AND pm.Recorded <= DATEADD(hh, 12, p.Admitted)
        ) AND EXISTS (
        SELECT  NULL
        FROM    PatientMeasurement pm
        WHERE   pm.PatientID = p.ID
                AND pm.Type = 'B'
                AND pm.Recorded <= DATEADD(hh, 12, p.Admitted)
        ) THEN 1 ELSE 0 END
FROM    Patient p
于 2009-11-13T16:42:56.110 に答える
1

別の解決策は、次を使用して元の試みに近い場合がありますOUTER APPLY

SELECT  PatientId, CASE WHEN a.cnt+b.cnt>2 THEN 1 ELSE 0 END Numerator, 1 Denominator 
FROM    patient p 
OUTER APPLY ( 
    SELECT      count(*) cnt 
    FROM        PatientMeasurement pm 
    WHERE       MeasurementId='A' 
    AND       Recorded <= dateadd(hh, 12, p.Admitted) 
    AND pm.PatientId = p.PatientId
) AS a(cnt)     
OUTER APPLY ( 
    SELECT      count(*) cnt 
    FROM        PatientMeasurement pm 
    WHERE       MeasurementId='B' 
    AND       Recorded <= dateadd(hh, 12, p.Admitted) 
    AND pm.PatientId = p.PatientId
) AS b(cnt)
于 2009-11-13T16:55:58.213 に答える
0

Sql 2005 または 2008 を使用していると仮定すると、いくつかのウィンドウ関数とピボットを使用してクエリ全体を簡素化できます。

with pData as
(
    select  count(*) over(partition by PatientId, MeasurementId) as cnt,
            PatientId, MeasurementId
    from    PatientMeasurement pm
    where   MeasurementId in('A','B')
    and     Recorded <= dateadd(hh, 12, Admitted)
)
select  PatientId, coalesce([A],0) as cntA, coalesce([B],0) as cntB,
        case when coalesce([A],0) + coalesce([B],0) > 2 then 1 else 0 end as Numerator,
        1 as Denominator
from    pData
pivot   (max(cnt) for MeasurementId in([A],[B])) pvt
于 2009-11-13T17:10:35.180 に答える
0
DECLARE @TimeSlot int;
SET @TimeSlot = 12;

WITH 
pt AS (
    SELECT p.PatientID, p.Admitted, m.MeasurementID, m.Recorded,
        CASE 
          WHEN m.Recorded <= dateadd(hh, @TimeSlot, p.Admitted) THEN 1 
          ELSE 0 
        END AS "InTimeSlot"
    FROM Patient AS p
    LEFT JOIN PatientMeasurement AS m ON p.PatientID = m.PatientID
),
cntA AS (
    SELECT PatientID, count(*) AS "A_count"
    FROM pt WHERE MeasurementID='A' AND InTimeSlot = 1
    GROUP BY PatientID
),
cntB AS (
    SELECT PatientID, count(*) AS "B_count"
    FROM pt WHERE MeasurementID='B' AND InTimeSlot = 1
    GROUP BY PatientID
),
cntAB AS (
    SELECT p.PatientID
          ,coalesce(a.A_count, 0) AS "A_cnt"
          ,coalesce(b.B_count, 0) AS "B_cnt"
    FROM Patient as p
    LEFT JOIN  cntA  AS a ON p.PatientID = a.PatientID
    LEFT JOIN  cntB  AS b ON p.PatientID = b.PatientID
),
cntN AS (
    SELECT PatientID,
        CASE WHEN A_cnt > 0 AND B_cnt > 0 THEN 1 ELSE 0 END AS Numerator
    FROM cntAB 
)
SELECT PatientID, Numerator, 1 AS Denominator FROM cntN
于 2009-11-13T17:29:42.990 に答える