我需要在第一个约会日期显示所有患者的信息。在这里,我附上了我所需的信息图片。请看看:
我解决了,但我想更有效地做。这是我的解决方案:
SELECT ROW_NUMBER() OVER(ORDER BY p.Name) SINo,
or1.PatientID RegNo,
p.Name PatientName,
or1.DataHead Diagnosis,
or1.AppointmentDate,
'First Appointment Date' = (
SELECT or2.AppointmentDate
FROM OPDConsultancyRepository AS or2
WHERE or2.OPDConsultancyRepositoryID = (
(
SELECT MIN(or3.OPDConsultancyRepositoryID)
FROM OPDConsultancyRepository AS or3
WHERE or3.DataType = 3
AND or3.DoctorID = 2139 AND or3.PatientID=or1.PatientID
GROUP BY
or3.PatientID
)
)
)
FROM OPDConsultancyRepository AS or1
INNER JOIN Patient AS p
ON p.PatientID = or1.PatientID
WHERE or1.DataType = 3
AND or1.DoctorID = 2139
ORDER BY
p.Name
执行计划:
Above query needs 6 sec to produce output.
那么我如何优化它的任何建议?
答案 0 :(得分:0)
我认为您想要一个窗口函数:
min(or1.AppointmentDate) over (partition by doctorid, datetype, patientid) as first_appointment_date
答案 1 :(得分:0)
尝试这样的事情:
SELECT
...
[First Appointment Date] =
min(iif(or1.DataType = 3 and or1.DoctorID = 2139, or1.AppointmentDate, null))
over(partition by or1.PatientID)
...
尽管我想知道DoctorID,但尝试维护您的逻辑
删除这部分看起来很诱人
和or1.DoctorID = 2139
答案 2 :(得分:0)
这可能对您有用-您需要在内部查询中使用Lead()和Lag()函数。
选项-2
如果您使用自我联接并使用CTE,则可以通过对性能有重大意义的查询来实现相同的目的。
答案 3 :(得分:0)
如果没有DDL和执行计划,就无法确切地说出是什么在拖慢您的速度。确实使您放慢速度的一件事是相关子查询。请注意本文:Hidden RBAR: Triangular Joins其次-输掉最后一个ORDER BY p.name
,您不需要。如果必须出于显示目的对输出进行排序,则让应用程序处理它。最后,您应该检查执行计划中最昂贵的内容,并在需要的地方添加索引。
我构建此查询的方式是首先使其到达一个位置,在此位置您所有的列都包括所有相关的PatientID和约会日期记录。
DECLARE @table TABLE (patientId INT, appointmentDate DATE);
INSERT @table VALUES (1,GETDATE()),(1,GETDATE()-3),(2,GETDATE()-10),(2,GETDATE()-20),
(3,GETDATE()-30),(4,GETDATE()-3),(4,GETDATE()),(4,GETDATE()-100);
SELECT t.patientId, t.appointmentDate FROM @table AS t;
您可能可以将逻辑转换为索引视图,并且UNIQUE CLUSTERED INDEX位于PatientID和约会日期上。然后将该查询转换为子查询,您有几种选择:
DECLARE @table TABLE (patientId INT, appointmentDate DATE);
INSERT @table VALUES (1,GETDATE()),(1,GETDATE()-3),(2,GETDATE()-10),(2,GETDATE()-20),
(3,GETDATE()-30),(4,GETDATE()-3),(4,GETDATE()),(4,GETDATE()-100);
-- Option #1 -- GROUP BY + MIN
SELECT t.patientId, MIN(t.appointmentDate)
FROM @table AS t
GROUP BY t.patientId;
-- Option #2 -- Partitioned ROW_NUMBER() filtered for WHERE rn=1 in subquery
SELECT
d.patientId,
d.appointmentDate
FROM
(
SELECT
t.patientId,
t.appointmentDate,
rn = ROW_NUMBER() OVER (PARTITION BY t.patientId ORDER BY appointmentDate)
FROM @table AS t
) AS d
WHERE d.rn = 1;
-- Option #3 -- TOP (1) WITH TIES + ROW_NUMBER()
SELECT TOP (1) WITH TIES t.*
FROM @table AS t
ORDER BY ROW_NUMBER() OVER (PARTITION BY t.patientId ORDER BY appointmentDate);