第一步是分离并删除授权和资格数据。提供的原始发布数据似乎是两者的交叉应用,可能来自较早的查询。
第二步是 数据中提供的 包含 结束日期加 1 天来 独有 包含 开始日期和 独有 和 NULLIF()
的组合 ISNULL()
用于保留特殊的 结束时间 9999-12-31
值。
在下面的代码中,我使用术语 ThruDate
来指代 包含 结束日期(仅用于显示),并 ToDate
指代 排他 结束日期(由逻辑使用)。
接下来,我们需要确定要测试的所有不同日期范围。这可以通过提取所有不同的开始日期和不包含结束日期、对它们进行排序,然后为每个间隔构建新的日期范围来完成。 LAG()
窗口函数用于获取要与当前数据相结合的先前日期以定义每个范围。
现在我们可以测试每个日期间隔是否与授权和资格日期范围重叠。重叠日期范围的标准测试是 Start1 < End2 AND Start2 < End1
。如果我们的样本间隔与授权行重叠,但不与资格行重叠,则我们已确定授权但不合格的间隔应包含在结果中。
所有计算均针对每个 ID 值独立完成。
最终的逻辑将是这样的:
-- Date range operations work much better when using "exclusive" end dates,
-- so we will calculate and use exclusive end dates for all range and overlap
-- logic, and only use the inclusive end dates for display.
--
-- To see the intermediate results:
-- Change the select to SELECT * and
-- Uncomment the WHERE clause.
WITH AuthDates AS (
SELECT DISTINCT -- Distinct is used here to dedup the original unnormalized data
ID_NUM AS Id,
AUTH_EFF_DATE AS AuthFromDate,
AUTH_EXP_DATE AS AuthThruDate, -- Inclusive
ISNULL(
DATEADD(day, 1, NULLIF(AUTH_EXP_DATE, '9999-12-31')),
'9999-12-31') AS AuthToDate -- Exclusive
FROM ADMITS
),
EligibilityDates AS ( -- Distinct is used here to dedup the original unnormalized data
SELECT DISTINCT
ID_NUM AS Id,
MEM_EFF_DATE AS EligFromDate,
MEM_EFF_DATE AS EligThruDate, -- Inclusive
ISNULL(
DATEADD(day, 1, NULLIF(MEM_EXP_DATE, '9999-12-31')),
'9999-12-31') AS EligToDate -- Exclusive
FROM ADMITS
),
DistinctDates AS (
SELECT DISTINCT U.Id, U.Date
FROM (
SELECT A.Id, V.Date
FROM AuthDates A
CROSS APPLY (VALUES (AuthFromDate), (AuthToDate)) V(Date)
UNION ALL -- (Yes, I could drop the ALL, but I prefer an explicit DISTINCT)
SELECT E.Id, V.Date
FROM EligibilityDates E
CROSS APPLY (VALUES (EligFromDate), (EligToDate)) V(Date)
) U
),
DateRanges AS (
SELECT
Id,
LAG(Date) OVER(PARTITION BY Id ORDER BY Date) AS FromDate,
ISNULL(
DATEADD(day, -1, NULLIF(Date, '9999-12-31')),
'9999-12-31') AS ThruDate,
Date AS ToDate
FROM DistinctDates
)
SELECT
A.Id,
A.AuthFromDate, A.AuthThruDate,
D.FromDate AS IneligibleFromDate, D.ThruDate AS IneligibleThruDate
FROM DateRanges D
LEFT JOIN AuthDates A
ON A.Id = D.Id
AND A.AuthFromDate < D.ToDate
AND A.AuthToDate > D.FromDate
LEFT JOIN EligibilityDates E
ON E.Id = D.Id
AND E.EligFromDate < D.ToDate
AND E.EligToDate > D.FromDate
WHERE A.ID IS NOT NULL -- Authorized
AND E.Id IS NULL -- But not eligible
ORDER BY
D.Id,
D.FromDate
可以通过将第一个条件更改 WHERE
为 LEFT JOIN
并将第二个条件更改 INNER JOIN
为 LEFT JOIN
当前 WHERE NOT EXISTS(...)
,但我将它们保留为外连接,以便可以轻松查看中间结果。)
中间结果(使用独占结束日期):
ID
|
从日期
|
迄今为止
|
验证日期
|
授权日期
|
资格起始日期
|
资格截止日期
|
118206307
|
无效的
|
2022-04-22
|
无效的
|
无效的
|
无效的
|
无效的
|
118206307
|
2022-04-22
|
2023-01-02
|
无效的
|
无效的
|
2022-04-22
|
2023-10-01
|
118206307
|
2023-01-02
|
2023-06-08
|
2023-01-02
|
2023-06-08
|
2022-04-22
|
2023-10-01
|
118206307
|
2023-06-08
|
2023-08-30
|
无效的
|
无效的
|
2022-04-22
|
2023-10-01
|
118206307
|
2023-08-30
|
2023-10-01
|
2023-08-30
|
2024-02-18
|
2022-04-22
|
2023-10-01
|
118206307
|
2023-10-01
|
2023-10-20
|
2023-08-30
|
2024-02-18
|
无效的
|
无效的
|
118206307
|
2023-10-20
|
2024-02-18
|
2023-08-30
|
2024-02-18
|
2023-10-20
|
9999-12-31
|
118206307
|
2024-02-18
|
9999-12-31
|
无效的
|
无效的
|
2023-10-20
|
9999-12-31
|
最终结果:
ID
|
验证日期
|
授权日期
|
不符合资格日期
|
截止日期不合格
|
118206307
|
2023-08-30
|
2024-02-17
|
2023-10-01
|
2023-10-19
|
请参阅 this db<>fiddle 的演示,其中包含涵盖多个重叠授权和资格场景的附加测试数据。