أتمنى أن أقوم بربط "عرض مضمن"
-
20-09-2019 - |
سؤال
لدي جدول مريض:
PatientId Admitted
--------- ---------------
1 d/m/yy hh:mm:ss
2 d/m/yy hh:mm:ss
3 d/m/yy hh:mm:ss
لدي جدول مريضا (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
أساسا، سيكون لدى المريض 1 في البسط إذا كان لديك قيمة واحدة على الأقل للقياس بقيمة واحدة وقيمة واحدة للقياس ب. في هذا المثال، يحتوي المريض 1 على 3 قياسات وتدابير 2 ب، وبالتالي فإن البسط هو 1. المريض 1. المريض 2 لديه 2 قياسات، ولكن لا قياسات B، وبالتالي فإن البسط هو 0. المريض ليس لديه قياس ولا قياس 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
يعمل هذا كما هو متوقع طالما أنني لا أقوم بتضمين تقييد التاريخ المرتبط (المسجل <dateadd (HH، 12، مقبول). لسوء الحظ، يربط "عرض مضمون" بهذه الطريقة غير صالحنة.
لقد أجبرني هذا على إعادة كتابة 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
سؤالي: هل هناك طريقة أفضل وأكثر فعالية للقيام بذلك؟
شكرا على وقتك.
المحلول
جرب هذا :
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'
لقد قدمت قرصا واحدا إلى منطق الأعمال أيضا - يقول المواصفات الخاصة بك إن البسط يجب أن يكون واحدا إذا كان المريض لديه كلا من قياسات A و B - ومع ذلك، فإن جملةك من A.CNT + B.CNT> 2 سيعود بشكل خاطئ إلى أي شيء إما .cnt أو b.cnt هي 3 أو أكثر والآخر صفر.
نصائح أخرى
حل آخر يمكن أن يكون قريبا من محاولتك الأصلية باستخدام 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)
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
على افتراض أنك تستخدم 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
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