在 SQL 中动态比较不同列和行中的日期
Compare dates in different columns and rows dynamically in SQL
我有这样一组数据
数据
ID Start_dt End_dt
A 1/1/2010 12/31/2010
A 1/1/2011 12/31/2011
A 6/1/2012 12/31/2012
A 1/1/2014 12/31/2014
A 1/1/2016 10/31/2016
A 1/1/2018 12/31/2018
B 1/1/2016 2/29/2016
B 3/1/2016 10/31/2016
B 1/1/2017 7/31/2017
B 1/1/2019 12/31/9999
C 1/1/2017 12/31/2017
C 1/1/2017 12/31/2018
C 1/1/2019 12/31/9999
我需要创建一个查询来查看每个成员的行,将当前 Start_dt 与之前的 End_dt 进行比较。如果差异小于一年,则将这 2 条记录视为一个连续注册和 return 合并的 MIN Start_dt 和 MAX End_dt,并对每个成员的所有行重复该操作。如果差异 >=1 年,则将其视为单独注册。
想要的结果
ID Start_dt End_dt
A 1/1/2010 12/31/2012
A 1/1/2014 12/31/2014
A 1/1/2016 10/31/2016
A 1/1/2018 12/31/2018
B 1/1/2016 7/31/2017
B 1/1/2019 12/31/2019
C 1/1/2017 12/31/9999
这是一个创建 Table 查询:
if OBJECT_ID ('tempdb..#test1') is not null
drop table #test1
CREATE TABLE #test1 (
ID varchar(10),
Start_dt datetime,
End_dt datetime
);
INSERT INTO #test1 VALUES ('A', '1/1/2010', '12/31/2010')
,('A', '1/1/2011', '12/31/2011')
,('A', '6/1/2012', '12/31/2012')
,('A', '1/1/2014', '12/31/2014')
,('A', '1/1/2016', '10/31/2016')
,('A', '1/1/2018', '12/31/2018')
,('B', '1/1/2016', '2/29/2016')
,('B', '3/1/2016', '10/31/2016')
,('B', '1/1/2017', '7/31/2017')
,('B', '1/1/2019', '12/31/9999')
,('C', '1/1/2017', '12/31/2017')
,('C', '1/1/2017', '12/31/2018')
,('C', '1/1/2019', '12/31/2999')
我已经尝试解决这个问题好几天了,但尝试过自连接、循环但没有找到好的解决方案。有人可以帮忙吗?
谢谢!
您可以使用 lag()
或累积 max()
来获取上一个结束日期。然后将其与当前开始日期进行比较。
当相差超过一年时,新组开始。对这些新分组开始做累加,得到一个分组id。
剩下的就是聚合:
select id, min(start_dt), max(end_dt)
from (select t1.*,
sum(case when prev_end_dt > dateadd(year, -1, start_dt) then 0 else 1 end) over
(partition by id order by start_dt) as grp
from (select t1.*,
max(end_dt) over (partition by id
order by start_dt
rows between unbounded preceding and 1 preceding
) as prev_end_dt
from test1 t1
) t1
) t1
group by id, grp
order by id, min(start_dt);
您可以试试这个查询
SELECT ID, StartDate, End_dt AS EndDate
FROM (
SELECT *
, LAG(End_dt) OVER(PARTITION BY ID ORDER BY ID, Start_dt, End_dt) AS PrevEnd
, DATEDIFF(DAY, LAG(End_dt) OVER(PARTITION BY ID ORDER BY ID, Start_dt, End_dt), Start_dt) AS DaysBreak
, (
CASE
WHEN DATEDIFF(DAY, LAG(End_dt) OVER(PARTITION BY ID ORDER BY ID, Start_dt, End_dt), Start_dt) > 365 THEN Start_dt
WHEN LAG(End_dt) OVER(PARTITION BY ID ORDER BY ID, Start_dt, End_dt) IS NULL THEN Start_dt
ELSE NULL
END
) AS StartDate
FROM #test1
) a
WHERE StartDate IS NOT NULL
我有这样一组数据
数据
ID Start_dt End_dt
A 1/1/2010 12/31/2010
A 1/1/2011 12/31/2011
A 6/1/2012 12/31/2012
A 1/1/2014 12/31/2014
A 1/1/2016 10/31/2016
A 1/1/2018 12/31/2018
B 1/1/2016 2/29/2016
B 3/1/2016 10/31/2016
B 1/1/2017 7/31/2017
B 1/1/2019 12/31/9999
C 1/1/2017 12/31/2017
C 1/1/2017 12/31/2018
C 1/1/2019 12/31/9999
我需要创建一个查询来查看每个成员的行,将当前 Start_dt 与之前的 End_dt 进行比较。如果差异小于一年,则将这 2 条记录视为一个连续注册和 return 合并的 MIN Start_dt 和 MAX End_dt,并对每个成员的所有行重复该操作。如果差异 >=1 年,则将其视为单独注册。
想要的结果
ID Start_dt End_dt
A 1/1/2010 12/31/2012
A 1/1/2014 12/31/2014
A 1/1/2016 10/31/2016
A 1/1/2018 12/31/2018
B 1/1/2016 7/31/2017
B 1/1/2019 12/31/2019
C 1/1/2017 12/31/9999
这是一个创建 Table 查询:
if OBJECT_ID ('tempdb..#test1') is not null
drop table #test1
CREATE TABLE #test1 (
ID varchar(10),
Start_dt datetime,
End_dt datetime
);
INSERT INTO #test1 VALUES ('A', '1/1/2010', '12/31/2010')
,('A', '1/1/2011', '12/31/2011')
,('A', '6/1/2012', '12/31/2012')
,('A', '1/1/2014', '12/31/2014')
,('A', '1/1/2016', '10/31/2016')
,('A', '1/1/2018', '12/31/2018')
,('B', '1/1/2016', '2/29/2016')
,('B', '3/1/2016', '10/31/2016')
,('B', '1/1/2017', '7/31/2017')
,('B', '1/1/2019', '12/31/9999')
,('C', '1/1/2017', '12/31/2017')
,('C', '1/1/2017', '12/31/2018')
,('C', '1/1/2019', '12/31/2999')
我已经尝试解决这个问题好几天了,但尝试过自连接、循环但没有找到好的解决方案。有人可以帮忙吗?
谢谢!
您可以使用 lag()
或累积 max()
来获取上一个结束日期。然后将其与当前开始日期进行比较。
当相差超过一年时,新组开始。对这些新分组开始做累加,得到一个分组id。
剩下的就是聚合:
select id, min(start_dt), max(end_dt)
from (select t1.*,
sum(case when prev_end_dt > dateadd(year, -1, start_dt) then 0 else 1 end) over
(partition by id order by start_dt) as grp
from (select t1.*,
max(end_dt) over (partition by id
order by start_dt
rows between unbounded preceding and 1 preceding
) as prev_end_dt
from test1 t1
) t1
) t1
group by id, grp
order by id, min(start_dt);
您可以试试这个查询
SELECT ID, StartDate, End_dt AS EndDate
FROM (
SELECT *
, LAG(End_dt) OVER(PARTITION BY ID ORDER BY ID, Start_dt, End_dt) AS PrevEnd
, DATEDIFF(DAY, LAG(End_dt) OVER(PARTITION BY ID ORDER BY ID, Start_dt, End_dt), Start_dt) AS DaysBreak
, (
CASE
WHEN DATEDIFF(DAY, LAG(End_dt) OVER(PARTITION BY ID ORDER BY ID, Start_dt, End_dt), Start_dt) > 365 THEN Start_dt
WHEN LAG(End_dt) OVER(PARTITION BY ID ORDER BY ID, Start_dt, End_dt) IS NULL THEN Start_dt
ELSE NULL
END
) AS StartDate
FROM #test1
) a
WHERE StartDate IS NOT NULL