SQL:标记新值;创建日期范围

时间:2018-05-03 13:26:04

标签: sql sql-server

我尝试使用SQL创建一个开始日期&结束日期显示每次Type列的值发生更改时(按ID排序)。我需要将相同类型的所有连续遭遇分组到相同的日期范围内,但每次类型更改时都会反映出来。

Current Data Format:
ID  Type    Date
1   A   1/1/2018
1   A   1/20/2018
1   B   3/15/2018
2   C   1/10/2018
2   A   1/12/2018
2   C   4/19/2018
3   B   2/10/2018
3   B   3/9/2018
3   D   5/1/2018

Desired Format:
ID  Type Start Date End Date 
1   A   1/1/2018    3/14/2018
1   B   3/15/2018   12/31/9999
2   C   1/10/2018   1/11/2018
2   A   1/12/2018   4/18/2018
2   C   4/19/2018   12/31/9999
3   B   2/10/2018   4/30/2018
3   D   5/1/2018    12/31/9999

我很乐意分享我尝试的代码(不同的索引类型,标志等),但老实说,甚至没有任何东西可以接近所需的格式。

2 个答案:

答案 0 :(得分:0)

这会产生您正在寻找的输出。请注意我是如何以可消费格式发布表格和样本数据的。您将来应该考虑类似的事情。这让其他人很容易提供帮助。

除非您是sql server 2012或更新版本,否则这将无效。如果您使用的是旧版本,那么仍然可以实现它,这将变得更具挑战性。

declare @Something table
(
    ID int
    , SomeType char(1)
    , SomeDate date
)

insert @Something values
(1, 'A', '1/1/2018')
, (1, 'A', '1/20/2018')
, (1, 'B', '3/15/2018')
, (2, 'C', '1/10/2018')
, (2, 'A', '1/12/2018')
, (2, 'C', '4/19/2018')
, (3, 'B', '2/10/2018')
, (3, 'B', '3/9/2018')
, (3, 'D', '5/1/2018')
;

with groups as
(
    select *
        , MyGroup = Lag(SomeType, 1) over(partition by ID order by SomeDate)
    from @Something s
)

select g.ID
    , Type = g.SomeType
    , StartDate = g.SomeDate
    , EndDate = isnull(dateadd(day, -1, Lead(SomeDate, 1) over(partition by ID order by SomeDate)), '99991231')
from groups g
where g.SomeType <> isnull(g.MyGroup, '')

答案 1 :(得分:0)

你可以使用它。

DECLARE @MyTable TABLE (ID  INT, Type VARCHAR(10),   [Date] DATE)
INSERT INTO @MyTable VALUES
(1, 'A', '1/1/2018'),
(1, 'A', '1/20/2018'),
(1, 'B', '3/15/2018'),
(2, 'C', '1/10/2018'),
(2, 'A', '1/12/2018'),
(2, 'C', '4/19/2018'),
(3, 'B', '2/10/2018'),
(3, 'B', '3/9/2018'),
(3, 'D', '5/1/2018')


;WITH CTE AS (
    SELECT  *, ROW_NUMBER() OVER(PARTITION BY Type, GRP ORDER BY [Date]) AS F 
    FROM (
        SELECT *, ROW_NUMBER() OVER(ORDER BY ID, [Date]) - ROW_NUMBER() OVER(PARTITION BY Type ORDER BY ID, [Date]) GRP
        FROM @MyTable
    ) AS T
)
, CTE2 AS (
    SELECT ROW_NUMBER() OVER(ORDER BY ID, [Date]) RN, * FROM CTE T1
    WHERE F= 1 
)
SELECT  T1.ID, T1.Type, T1.[Date] [Start Date], ISNULL(DATEADD(DAY,-1,T2.[Date]),'99991231') [End Date]
FROM CTE2 AS T1
    LEFT JOIN CTE2 AS T2 ON T1.ID = T2.ID AND T1.RN = T2.RN - 1
ORDER BY T1.ID, T1.[Date]

结果:

ID          Type       Start Date End Date
----------- ---------- ---------- ----------
1           A          2018-01-01 2018-03-14
1           B          2018-03-15 9999-12-31
2           C          2018-01-10 2018-01-11
2           A          2018-01-12 2018-04-18
2           C          2018-04-19 9999-12-31
3           B          2018-02-10 2018-04-30
3           D          2018-05-01 9999-12-31