【发布时间】:2016-10-05 11:43:00
【问题描述】:
我正在使用 SQL Server 2008 并试图提高下面查询的速度。该查询根据再入院日期为患者分配积分。
示例:患者于 1/2、1/5、1/7、1/8、1/9、2/4 就诊。我想在 3 天内进行第一次团体访问。 1/2-5分组,1/7-9分组。 1/5 不与 1/7 分组,因为 1/5 的实际访问日期是 1/2。 1/7 将获得 3 分,因为它是 1/2 的重新录取。 2/4 也将获得 3 分,因为它是 1/7 的重新录取。当日期分组时,第一个日期是实际访问日期。
大多数文章建议限制数据集或添加索引以提高速度。我将行数限制在 15,000 左右并添加了一个索引。当运行具有 45 个测试访问日期/3 个测试患者的查询时,查询需要 1.5 分钟才能运行。使用我的实际数据集需要 > 8 小时。 我怎样才能让这个查询运行
查询下方的示例预期结果。
;CREATE TABLE RiskReadmits(MRN INT, VisitDate DATE, Category VARCHAR(15))
;CREATE CLUSTERED INDEX Risk_Readmits_Index ON RiskReadmits(VisitDate)
;INSERT RiskReadmits(MRN,VisitDate,CATEGORY)
VALUES
(1, '1/2/2016','Inpatient'),
(1, '1/5/2016','Inpatient'),
(1, '1/7/2016','Inpatient'),
(1, '1/8/2016','Inpatient'),
(1, '1/9/2016','Inpatient'),
(1, '2/4/2016','Inpatient'),
(1, '6/2/2016','Inpatient'),
(1, '6/3/2016','Inpatient'),
(1, '6/5/2016','Inpatient'),
(1, '6/6/2016','Inpatient'),
(1, '6/8/2016','Inpatient'),
(1, '7/1/2016','Inpatient'),
(1, '8/1/2016','Inpatient'),
(1, '8/4/2016','Inpatient'),
(1, '8/15/2016','Inpatient'),
(1, '8/18/2016','Inpatient'),
(1, '8/28/2016','Inpatient'),
(1, '10/12/2016','Inpatient'),
(1, '10/15/2016','Inpatient'),
(1, '11/17/2016','Inpatient'),
(1, '12/20/2016','Inpatient')
;WITH a AS (
SELECT
z1.VisitDate
, z1.MRN
, (SELECT MIN(VisitDate) FROM RiskReadmits WHERE VisitDate > DATEADD(day, 3, z1.VisitDate)) AS NextDay
FROM
RiskReadmits z1
WHERE
CATEGORY = 'Inpatient'
), a1 AS (
SELECT
MRN
, MIN(VisitDate) AS VisitDate
, MIN(NextDay) AS NextDay
FROM
a
GROUP BY
MRN
), b AS (
SELECT
VisitDate
, MRN
, NextDay
, 1 AS OrderRow
FROM
a1
UNION ALL
SELECT
a.VisitDate
, a.MRN
, a.NextDay
, b.OrderRow +1 AS OrderRow
FROM
a
JOIN b
ON a.VisitDate = b.NextDay
), c AS (
SELECT
MRN,
VisitDate
, (SELECT MAX(VisitDate) FROM b WHERE b1.VisitDate > VisitDate AND b.MRN = b1.MRN) AS PreviousVisitDate
FROM
b b1
)
SELECT distinct
c1.MRN,
c1.VisitDate
, CASE
WHEN DATEDIFF(day,c1.PreviousVisitDate,c1.VisitDate) < 30 THEN PreviousVisitDate
ELSE NULL
END AS ReAdmissionFrom
, CASE
WHEN DATEDIFF(day,c1.PreviousVisitDate,c1.VisitDate) < 30 THEN 3
ELSE 0
END AS Points
FROM
c c1
ORDER BY c1.MRN
预期结果:
MRN VisitDate ReAdmissionFrom Points
1 2016-01-02 NULL 0
1 2016-01-07 2016-01-02 3
1 2016-02-04 2016-01-07 3
1 2016-06-02 NULL 0
1 2016-06-06 2016-06-02 3
1 2016-07-01 2016-06-06 3
1 2016-08-01 NULL 0
1 2016-08-15 2016-08-01 3
1 2016-08-28 2016-08-15 3
1 2016-10-12 NULL 0
1 2016-11-17 NULL 0
1 2016-12-20 NULL 0
【问题讨论】:
-
您应该描述您正在尝试做的事情,包括样本数据和期望的结果。
-
我还建议您将其发布到 codereview.stackexchange.com 站点
-
我继续发布了我的预期结果。
-
如果1日、3日、4日有访问怎么办?您将其视为 1 日的访问,忽略 3 日的访问,然后在 4 日重新入院。但是为什么不能一号就诊,三号再入院呢?如果您可以可靠地确认某些访问被忽略的原因的业务逻辑,那么肯定有更快的方法来编写您的查询。
标签: sql sql-server recursion common-table-expression recursive-query