SQL:差距和岛屿,分组日期
SQL: Gaps and Islands, Grouped dates
我正在尝试将日期分组在 3 天内,并根据 30 天内的再入院分配分数。 MRN 每次重新入院将获得 3 分。在下面修改我的查询的任何帮助都会很棒。
示例:
CREATE TABLE #z (
ID INT IDENTITY(1,1),
OrganizationMrn INT,
VisitDate DATE,
CATEGORY VARCHAR(15) )
INSERT #z(OrganizationMrn, 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')
期望输出:我真的只需要实际访问次数、OrganizationMrn 和积分。
(日期分组时(实际访问),第一个日期应用于 30 天内的再入院)。
ACTUAL Visits Grouped Dates Re-admissions Points
1/2/2016 (grouped 1/2, 1/5)
1/7/2016 (grouped 1/7, 1/8, 1/9) Readmit from 1/2 (3 points)
2/4/2016 Readmit from 1/7 (3 points)
6/2/2016 (grouped 6/2, 6/3, 6/5)
6/6/2016 (grouped 6/6, 6/8) Readmit from 6/2 (3 points)
7/1/2016 Readmit from 6/6 (3 points)
8/1/2016 (grouped 8/1, 8/4)
8/15/2016 (grouped 8/15, 8/18) Readmit from 8/1 (3 points)
8/28/2016 Readmit from 8/15 (3 points)
10/12/2016 (grouped 10/12, 10/15)
11/17/2016
12/20/2016
___________________________________________ 6 total readmits (18 total points)
下面的查询使用 gaps 和 islands 对彼此相隔 3 天以内的日期进行分组。但是,如果日期是连续的,则开始/结束日期被分组。(示例:下面的查询将 [1/2, 1/5, 1/7/, 1/8, 1/9] 分组为一行;日期应分为两行 [1/2, 1/5] 和 [1/7/, 1/8, 1/9])。
一旦分组的日期有单独的行,我需要在 30 天内为每次重新入院分配 3 分。 (每个 OrganizationMrn 的实际访问彼此相隔 30 天)。上面所需的输出部分描述了我的示例中的日期应该如何分组。
;WITH StartingPoints AS (
SELECT OrganizationMrn, VisitDate, ROW_NUMBER() OVER (ORDER BY VisitDate) AS Sequence FROM #z AS A
WHERE a.category = 'Inpatient' AND NOT EXISTS (
SELECT * FROM #z AS B
WHERE B.OrganizationMrn = A.OrganizationMrn AND
B.VisitDate >= DATEADD(DAY, -4, A.VisitDate) AND
B.VisitDate < A.VisitDate AND
B.Category = 'Inpatient' ) ),
EndingPoints AS (
SELECT OrganizationMrn, VisitDate, ROW_NUMBER() OVER (ORDER BY VisitDate) AS Sequence FROM #z AS A
WHERE a.category = 'Inpatient' AND NOT EXISTS (
SELECT * FROM #z AS B
WHERE B.OrganizationMrn = A.OrganizationMrn AND
B.VisitDate <= DATEADD(DAY, 4, A.VisitDate) AND
B.VisitDate > A.VisitDate AND
B.Category = 'Inpatient' ) )
SELECT S.OrganizationMrn, S.VisitDate AS StartDate, E.VisitDate AS EndDate, CEILING((DATEDIFF(DAY, S.VisitDate, E.VisitDate) + 1) / 4.0) AS Points
FROM StartingPoints AS S
JOIN EndingPoints AS E ON (E.Sequence = S.Sequence)
ORDER BY S.OrganizationMrn DESC
此答案适用于您提供的示例。如果您的桌子很小且入场人数有限,这可能会很有用。 (它在日期上使用递归)。
WITH a AS (
SELECT
z1.VisitDate
, z1.OrganizationMrn
, (SELECT MIN(VisitDate) FROM #z WHERE VisitDate > DATEADD(day, 3, z1.VisitDate)) AS NextDay
FROM
#z z1
WHERE
CATEGORY = 'Inpatient'
), a1 AS (
SELECT
OrganizationMrn
, MIN(VisitDate) AS VisitDate
, MIN(NextDay) AS NextDay
FROM
a
GROUP BY
OrganizationMrn
), b AS (
SELECT
VisitDate
, OrganizationMrn
, NextDay
, 1 AS OrderRow
FROM
a1
UNION ALL
SELECT
a.VisitDate
, a.OrganizationMrn
, a.NextDay
, b.OrderRow +1 AS OrderRow
FROM
a
JOIN b
ON a.VisitDate = b.NextDay
), c AS (
SELECT
VisitDate
, (SELECT MAX(VisitDate) FROM b WHERE b1.VisitDate > VisitDate) AS PreviousVisitDate
FROM
b b1
)
SELECT
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
我正在尝试将日期分组在 3 天内,并根据 30 天内的再入院分配分数。 MRN 每次重新入院将获得 3 分。在下面修改我的查询的任何帮助都会很棒。
示例:
CREATE TABLE #z (
ID INT IDENTITY(1,1),
OrganizationMrn INT,
VisitDate DATE,
CATEGORY VARCHAR(15) )
INSERT #z(OrganizationMrn, 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')
期望输出:我真的只需要实际访问次数、OrganizationMrn 和积分。 (日期分组时(实际访问),第一个日期应用于 30 天内的再入院)。
ACTUAL Visits Grouped Dates Re-admissions Points
1/2/2016 (grouped 1/2, 1/5)
1/7/2016 (grouped 1/7, 1/8, 1/9) Readmit from 1/2 (3 points)
2/4/2016 Readmit from 1/7 (3 points)
6/2/2016 (grouped 6/2, 6/3, 6/5)
6/6/2016 (grouped 6/6, 6/8) Readmit from 6/2 (3 points)
7/1/2016 Readmit from 6/6 (3 points)
8/1/2016 (grouped 8/1, 8/4)
8/15/2016 (grouped 8/15, 8/18) Readmit from 8/1 (3 points)
8/28/2016 Readmit from 8/15 (3 points)
10/12/2016 (grouped 10/12, 10/15)
11/17/2016
12/20/2016
___________________________________________ 6 total readmits (18 total points)
下面的查询使用 gaps 和 islands 对彼此相隔 3 天以内的日期进行分组。但是,如果日期是连续的,则开始/结束日期被分组。(示例:下面的查询将 [1/2, 1/5, 1/7/, 1/8, 1/9] 分组为一行;日期应分为两行 [1/2, 1/5] 和 [1/7/, 1/8, 1/9])。
一旦分组的日期有单独的行,我需要在 30 天内为每次重新入院分配 3 分。 (每个 OrganizationMrn 的实际访问彼此相隔 30 天)。上面所需的输出部分描述了我的示例中的日期应该如何分组。
;WITH StartingPoints AS (
SELECT OrganizationMrn, VisitDate, ROW_NUMBER() OVER (ORDER BY VisitDate) AS Sequence FROM #z AS A
WHERE a.category = 'Inpatient' AND NOT EXISTS (
SELECT * FROM #z AS B
WHERE B.OrganizationMrn = A.OrganizationMrn AND
B.VisitDate >= DATEADD(DAY, -4, A.VisitDate) AND
B.VisitDate < A.VisitDate AND
B.Category = 'Inpatient' ) ),
EndingPoints AS (
SELECT OrganizationMrn, VisitDate, ROW_NUMBER() OVER (ORDER BY VisitDate) AS Sequence FROM #z AS A
WHERE a.category = 'Inpatient' AND NOT EXISTS (
SELECT * FROM #z AS B
WHERE B.OrganizationMrn = A.OrganizationMrn AND
B.VisitDate <= DATEADD(DAY, 4, A.VisitDate) AND
B.VisitDate > A.VisitDate AND
B.Category = 'Inpatient' ) )
SELECT S.OrganizationMrn, S.VisitDate AS StartDate, E.VisitDate AS EndDate, CEILING((DATEDIFF(DAY, S.VisitDate, E.VisitDate) + 1) / 4.0) AS Points
FROM StartingPoints AS S
JOIN EndingPoints AS E ON (E.Sequence = S.Sequence)
ORDER BY S.OrganizationMrn DESC
此答案适用于您提供的示例。如果您的桌子很小且入场人数有限,这可能会很有用。 (它在日期上使用递归)。
WITH a AS (
SELECT
z1.VisitDate
, z1.OrganizationMrn
, (SELECT MIN(VisitDate) FROM #z WHERE VisitDate > DATEADD(day, 3, z1.VisitDate)) AS NextDay
FROM
#z z1
WHERE
CATEGORY = 'Inpatient'
), a1 AS (
SELECT
OrganizationMrn
, MIN(VisitDate) AS VisitDate
, MIN(NextDay) AS NextDay
FROM
a
GROUP BY
OrganizationMrn
), b AS (
SELECT
VisitDate
, OrganizationMrn
, NextDay
, 1 AS OrderRow
FROM
a1
UNION ALL
SELECT
a.VisitDate
, a.OrganizationMrn
, a.NextDay
, b.OrderRow +1 AS OrderRow
FROM
a
JOIN b
ON a.VisitDate = b.NextDay
), c AS (
SELECT
VisitDate
, (SELECT MAX(VisitDate) FROM b WHERE b1.VisitDate > VisitDate) AS PreviousVisitDate
FROM
b b1
)
SELECT
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