SQL Server-将每天的记录转换为日期范围(有间隔)

时间:2019-01-14 16:00:19

标签: sql-server tsql

我发现了很多问题和答案,询问如何将日期范围转换为每天的记录,但是我需要相反的操作,并且找不到任何东西。

所以说我有这个数据集:

User | Available
1    | 01-01-2019
1    | 02-01-2019
1    | 03-01-2019
1    | 04-01-2019
2    | 05-01-2019
2    | 06-01-2019
2    | 07-01-2019
2    | 10-01-2019
2    | 11-01-2019
2    | 12-01-2019

因此我们有一个用户1,该用户在2019年01月01日到2019年4月1日之间可以使用。然后我们有用户2,其可用时间为05/01/2019至07/01/2019和10/01/2019至12/01/2019。

我正在寻找的结果应如下所示:

User | Start      | End
1    | 01-01-2019 | 04-01-2019
2    | 05-01-2019 | 07-01-2019
2    | 10-01-2019 | 12-01-2019

使用最小/最大日期来计算用户1相当容易,但是由于用户2的间隔,我完全迷失了。有什么建议吗?

3 个答案:

答案 0 :(得分:3)

我也必须在某个地方这样做,这是我使用的解决方案。基本上使用按分组列划分并按日期排序的行号,并另外计算从特定日期开始的天数(任何硬编码的日期都可以)。

此处的关键是,当行数增加1乘1时,如果日期连续,锚点差异将仅增加1乘1。因此,只有在存在连续日期的情况下,锚点diff和行号之间的其余部分才会 保持不变 ,从而允许您分组并计算最小值/最大值。

IF OBJECT_ID('tempdb..#Availabilities') IS NOT NULL
    DROP TABLE #Availabilities

CREATE TABLE #Availabilities (
    [User] INT,
    Available DATE)

INSERT INTO #Availabilities
VALUES
    (1, '2019-01-01'),
    (1, '2019-01-02'),
    (1, '2019-01-03'),
    (1, '2019-01-04'),

    (2, '2019-01-05'),
    (2, '2019-01-06'),
    (2, '2019-01-07'),

    (2, '2019-01-10'),
    (2, '2019-01-11'),
    (2, '2019-01-12')


;WITH WindowFunctions AS
(
    SELECT
        A.[User],
        A.Available,
        AnchorDayDifference = DATEDIFF(DAY, '2018-01-01', A.Available),
        RowNumber = ROW_NUMBER() OVER (PARTITION BY A.[User] ORDER BY A.Available)
    FROM
        #Availabilities AS A
)
SELECT
    T.[User],
    Start = MIN(T.Available),
    [End] = MAX(T.Available)
FROM
    WindowFunctions AS T
GROUP BY
    T.[User],
    T.AnchorDayDifference - T.RowNumber

结果:

User    Start       End
1       2019-01-01  2019-01-04
2       2019-01-05  2019-01-07
2       2019-01-10  2019-01-12

{WindowFunctions值是(加上后休息结果):

User    Available   AnchorDayDifference RowNumber   GroupingRestResult
1       2019-01-01  365                 1           364
1       2019-01-02  366                 2           364
1       2019-01-03  367                 3           364
1       2019-01-04  368                 4           364
2       2019-01-05  369                 1           368
2       2019-01-06  370                 2           368
2       2019-01-07  371                 3           368
2       2019-01-10  374                 4           370
2       2019-01-11  375                 5           370
2       2019-01-12  376                 6           370

答案 1 :(得分:2)

这是一个“常见”的团体和岛屿问题。假设您使用的是SQL Server 2012+(如果不是,则是时候进行升级了),这将为您带来想要的结果:

USE Sandbox;
GO
WITH VTE AS(
    SELECT V.[User],
           CONVERT(date,Available,105) AS Available
    FROM (VALUES(1,'01-01-2019'),
                (1,'02-01-2019'),
                (1,'03-01-2019'),
                (1,'04-01-2019'),
                (2,'05-01-2019'),
                (2,'06-01-2019'),
                (2,'07-01-2019'),
                (2,'10-01-2019'),
                (2,'11-01-2019'),
                (2,'12-01-2019')) V([User],Available)),
Diffs AS(
    SELECT V.[User],
           V.Available,
           DATEDIFF(DAY, LAG(V.Available,1,DATEADD(DAY, -1, V.Available)) OVER (PARTITION BY V.[User] ORDER BY V.Available), V.Available) AS Diff
    FROM VTE V),
Groups AS(
    SELECT D.[User],
           D.Available,
           COUNT(CASE WHEN D.Diff > 1 THEN 1 END) OVER (PARTITION BY D.[User] ORDER BY D.Available
                                                        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Grp
    FROM Diffs D)
SELECT G.[User],
       MIN(G.Available) AS [Start],
       MAX(G.Available) AS [End]
FROM Groups G
GROUP BY G.[User],
         G.Grp
ORDER BY G.[User],
         [Start];

第一个CTE Diffs,不包括示例数据的VTE(“值表表达式”),得出不同行之间的天数差异。然后,第二个CTE Groups将日期分为几组(惊奇的是),基于差​​异是否大于1。然后我们可以使用这些组分别获得MINMAX最终SELECT中的那个组。

答案 2 :(得分:1)

我读的是MONTHS,不是DAYS

示例

Select [User]
      ,[Start] = min([Available])
      ,[End]   = max([Available])
 From ( 
        Select * 
              ,Grp = DateDiff(MONTH,'1900-01-01',[Available]) - Row_Number() over (Partition By [User] Order by [Available])
         From  YourTable
      ) A
 Group By [User],[Grp]

返回

User    Start       End
1       2019-01-01  2019-04-01
2       2019-05-01  2019-07-01
2       2019-10-01  2019-12-01