在SQL中动态比较不同列和行中的日期

时间:2019-03-19 17:57:31

标签: sql tsql ssms

我有一组这样的数据。

数据

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条记录视为一次连续注册,并返回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

这是一个创建表查询:

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')

几天来我一直在试图解决这个问题,但是我尝试过自联接,循环但没有找到好的解决方案。有人可以帮忙吗?

谢谢!

2 个答案:

答案 0 :(得分:1)

您可以使用private KWLinkedList <String> myList; @Before public void setUp() throws Exception { myList = new KWLinkedList<String>(); myList.add("Top"); myList.add("Mid"); myList.add("Jg"); myList.add("Sup"); myList.add("Adc"); ListIterator <String> myIter = myList.listIterator(); } @Test public void testlistiterator() { myList.listIterator(2); assertEquals(myList.next(),"Mid"); } 或累积lag()来获取上一个结束日期。然后将其与当前开始日期进行比较。

当差异超过一年时,就会开始一个新的组。对这些新组进行累积总和,即可开始获得分组ID。

剩下的就是聚合:

max()

答案 1 :(得分:0)

您可以尝试此查询

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