Pregunta

Tengo una tabla del paciente:

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

Tengo una tabla PatientMeasurement (0 a muchos):

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

Estoy tratando de crear un conjunto de resultados que se asemeja a:

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

Esencialmente, un paciente tendrá una 1 en el numerador si el tener al menos un valor para la medida de A y un valor para la medida B. En este ejemplo, el paciente 1 tiene 3 mediciones A y 2 B medidas, por lo que el numerador es 1. el paciente 2 tiene 2 mediciones a, pero no hay mediciones de B, por lo que el numerador es 0. el paciente tiene ni una una medición ni una medición B, por lo que el numerador es 0.

Mi consulta hasta el momento es:

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

Esto funciona como se espera, siempre y cuando no incluyo la, restricción de fecha correlacionada (grabado

Esto me ha obligado a volver a escribir el SQL para:

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

Mi pregunta:? ¿Hay una forma mejor y más eficiente de hacer esto

Gracias por su tiempo.

¿Fue útil?

Solución

Prueba esto:

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'

He hecho un pellizco a la lógica de negocio también - su especificación dice numerador debe ser uno si un paciente tiene ambas mediciones A y B - sin embargo, su cláusula de a.cnt + b.cnt> 2 será erróneamente devolver uno si cualquiera a.cnt o b.cnt son 3 o más y el otro es cero.

Otros consejos

Otra solución puede estar cerca de su uso OUTER APPLY intento inicial:

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)
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

Suponiendo que está utilizando SQL 2005 o 2008, toda la consulta se puede simplificar el uso de algunas funciones de la ventana y un pivote:

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
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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top