T-SQL - 我可以强制 ROW_NUMBER() OVER (PARTITION BY... 从设定点对记录进行编号吗?
Posted
技术标签:
【中文标题】T-SQL - 我可以强制 ROW_NUMBER() OVER (PARTITION BY... 从设定点对记录进行编号吗?【英文标题】:T-SQL - Can I force ROW_NUMBER() OVER (PARTITION BY... to number records from a set point? 【发布时间】:2018-01-22 12:19:14 【问题描述】:我有一张表格,其中包含患者预约列表:他们就诊的诊所和就诊日期。
我正在尝试编写一个查询,它提供以下信息:
“哪些患者在 2016 年 4 月至 2017 年 3 月期间的任何时候到过诊所 '123-45',以及该患者随后的两次预约(预约日期和就诊的诊所)是什么”? em>
我试图通过首先查询在时间范围内就诊于诊所“123-45”的所有患者的患者 ID 号列表,然后将此患者 ID 列表放入 WHERE 子句中来解决这个问题并使用ROW_NUMBER() OVER (PARTITION BY…
为我提供12 个月期间每位患者的所有预约的有序列表。
SELECT
x.Patient_Id
,x.Clinic_Code
,x.Appointment_Date
,x.Row_No FROM
(
SELECT
Patient_Id
,Clinic_Code
,Appointment_Date
,ROW_NUMBER() OVER (PARTITION BY Patient_Id ORDER BY Patient_Id, Appointment_Date asc) [Row_No]
FROM
Appointments
WHERE
Appointment_Date BETWEEN '01/10/2016' AND '30/09/2017'
AND Patient_ID = 'BLO123'
) x
WHERE x.Row_No < 4
但是,这会产生意想不到的后果,即对诊所“123-45”就诊之前发生的任何预约进行编号。
所以,如果以下是我的来源:
Patient_ID | Clinic_Code | Appointment_Date
--------------------------------------------
BLO123 | QWE-QW | 01-04-2016
BLO123 | OPD-ZZ | 05-10-2016
BLO123 | 123-45 | 13-11-2016
BLO123 | 333-44 | 15-12-2016
BLO123 | 999-45 | 02-02-2017
BLO123 | 222-44 | 15-02-2017
BLO123 | 777-45 | 19-03-2017
我想要得到的是:
Patient_ID | Clinic_Code | Appointment_Date | Row_No
--------------------------------------------------------------
BLO123 | 123-45 | 13-11-2016 | 1
BLO123 | 333-44 | 15-12-2016 | 2
BLO123 | 999-45 | 02-02-2017 | 3
但是通过在日期范围内包含之前的约会,我得到的是:
Patient_ID | Clinic_Code | Appointment_Date | Row_No
--------------------------------------------------------------
BLO123 | QWE-QW | 01-04-2016 | 1
BLO123 | OPD-ZZ | 05-10-2016 | 2
BLO123 | 123-45 | 13-11-2016 | 3
我想查询的是忽略在“123-45 就诊”之前的任何诊所预约。 请任何人都可以建议是否可以这样做?
【问题讨论】:
脱机;强烈反对在 where 子句中使用dd/mm/yyyy
作为 date format。
【参考方案1】:
此方法使用common table expression (CTE) 查找每位患者在诊所123-45
的第一次预约。查询主体返回所有后续约会。
样本数据:
DECLARE @Appointment TABLE
(
Patient_ID varchar(6),
Clinic_code varchar(6),
Appointment_Date date
)
;
INSERT INTO @Appointment
(
Patient_ID,
Clinic_code,
Appointment_Date
)
VALUES
('BLO123','QWE-QW','20160401'),
('BLO123','OPD-ZZ','20161005'),
('BLO123','123-45','20161113'),
('BLO123','333-44','20161215'),
('BLO123','999-45','20170202')
;
查询:
WITH
FirstAppointment AS
(
-- Find patients first vist to clinic 123-45.
SELECT
Patient_ID,
MIN(Appointment_Date) AS FirstAppointment_Date
FROM
@Appointment
WHERE
Appointment_Date >= '20160401'
AND Appointment_Date <= '20170331'
AND Clinic_code = '123-45'
GROUP BY
Patient_ID
)
SELECT
ROW_NUMBER() OVER (PARTITION BY a.Patient_ID ORDER BY a.Appointment_Date) AS Rn,
a.*
FROM
FirstAppointment AS fa
INNER JOIN @Appointment AS a ON a.Patient_ID = fa.Patient_ID
AND a.Appointment_Date >= fa.FirstAppointment_Date
;
【讨论】:
【参考方案2】:with foo as
(
select
*
from (values
('BLO123','QWE-QW', cast('20160401' as date))
,('BLO123','OPD-ZZ',cast('20161005' as date))
,('BLO123','123-45',cast('20161113' as date))
,('BLO123','333-44',cast('20161215' as date))
,('BLO123','999-45',cast('20170202' as date))
) a(Patient_ID , Clinic_Code , Appointment_Date)
)
,lags as
(
select
*
,lag(Clinic_code,1) over (partition by Patient_id order by Appointment_Date) l1
,lag(Clinic_code,2) over (partition by Patient_id order by Appointment_Date) l2
,ROW_NUMBER() over (partition by Patient_id order by Appointment_Date) rn
from foo
)
select Patient_ID,Clinic_Code,Appointment_Date
,case when Clinic_Code='123-45' then 1
when l1='123-45' then 2
else 3 end Row_Nr
from lags
where '123-45' in (Clinic_Code,l1,l2)
结果:
+----------------------------------------------+
|Patient_ID|Clinic_Code|Appointment_Date|Row_No|
+----------------------------------------------+
|BLO123 |123-45 |2016-11-13 |1 |
|BLO123 |333-44 |2016-12-15 |2 |
|BLO123 |999-45 |2017-02-02 |3 |
+----------------------------------------------+
【讨论】:
谢谢,但恐怕我在 SQL Server 2008 上,而且显然要到 2012 年才能使用 LAG 功能。以上是关于T-SQL - 我可以强制 ROW_NUMBER() OVER (PARTITION BY... 从设定点对记录进行编号吗?的主要内容,如果未能解决你的问题,请参考以下文章