【问题标题】:Get date range gaps from a date set从日期集中获取日期范围间隔
【发布时间】:2019-02-11 05:13:18
【问题描述】:

这是我们的集合

Date
-----------
2018-04-01
2018-04-02
2018-04-18
2018-04-19
2018-04-21
2018-04-22
2018-04-23
2018-04-24
2018-04-25
2018-04-26
2018-04-27
2018-04-28
2018-04-29
2018-05-05
2018-05-06
2018-05-07
2018-05-08
2018-05-09
2018-05-28
2018-05-29
2018-05-30
2018-05-31

我们希望每个月都缺少日期范围。所以输出会是这样的:

start_date    end_date
------------------------
2018-04-03    2018-04-17
2018-04-20    2018-04-20
2018-04-30    2018-04-30
2018-05-01    2018-05-04
2018-05-10    2018-05-27

请注意,我们在 2018-04-30 到 2018-05-04 之间缺少日期,但输出应分别在每个月范围内。

谢谢。

【问题讨论】:

  • calendar table 将使这项任务变得简单到难以置信。
  • @ZoharPeled 我浪费了 30 分钟吗?是的...可能:P 做到了
  • @TimBiegeleisen 你不妨决定关闭,因为其他一些差距和孤岛问题......不,你没有浪费你的时间,你只是创造了别人的生活更容易(希望如此)。

标签: sql sql-server tsql sql-server-2016


【解决方案1】:

这是一个典型的间隙和孤岛问题。我选择使用相关子查询来解决这个问题:

WITH cte AS (
    SELECT t1.Date, ROW_NUMBER() OVER (ORDER BY t1.Date) rn,
    FROM yourTable t1
    WHERE NOT EXISTS (SELECT TOP 1 t2.Date FROM yourTable t2
                      WHERE t2.Date = DATEADD(day, -1, t1.Date)) OR
          NOT EXISTS (SELECT TOP 1 t2.Date FROM yourTable t2
                      WHERE t2.Date = DATEADD(day, 1, t1.Date))
)

SELECT
    DATEADD(day, 1, MIN(Date)) AS start_date,
    DATEADD(day, -1, MAX(Date)) AS end_date
FROM cte
WHERE rn > 1
GROUP BY rn / 2
HAVING MIN(Date) <> MAX(Date);

Demo

【讨论】:

    【解决方案2】:

    如果你只是想不分月,你可以尝试如下。

    SELECT Dateadd(day, 1, [date])       start_date, 
           Dateadd(day, tbg - 1, [date]) end_date 
    FROM   (SELECT *, 
                   Datediff(day, [date], Lead([date]) OVER (ORDER BY [date])) TBG 
            FROM   @Date) T 
    WHERE  T.tbg > 1 
    

    输出(不考虑重叠月份)

    +------------+------------+
    | start_date | end_date   |
    +------------+------------+
    | 2018-04-03 | 2018-04-17 |
    +------------+------------+
    | 2018-04-20 | 2018-04-20 |
    +------------+------------+
    | 2018-04-30 | 2018-05-04 |
    +------------+------------+
    | 2018-05-10 | 2018-05-27 |
    +------------+------------+
    

    如果要拆分月份之间重叠的行,可以尝试如下。

    ;WITH cte 
         AS (SELECT *, 
                    Datediff(month, start_date, end_date) md 
             FROM   (SELECT Dateadd(day, 1, [date])       start_date, 
                            Dateadd(day, tbg - 1, [date]) end_date 
                     FROM   (SELECT *, 
                                    Datediff(day, [date], Lead([date]) 
                                                            OVER ( 
                                                              ORDER BY [date])) TBG 
                             FROM   @Date) T 
                     WHERE  T.tbg > 1) t2) 
    SELECT Cast(start_date AS DATE) start_date, 
           Cast(end_date AS DATE)   end_date 
    FROM   (SELECT start_date, 
                   end_date 
            FROM   cte C1 
            WHERE  md = 0 
            UNION ALL 
            SELECT CASE 
                     WHEN t.n = 1 THEN start_date 
                     ELSE Dateadd(mm, Datediff(mm, 0, end_date), 0) 
                   END AS start_date, 
                   CASE 
                     WHEN t.n = 2 THEN end_date 
                     ELSE Dateadd (dd, -1, Dateadd(mm, Datediff(mm, 0, start_date) + 
                                                       1, 0)) 
                   END AS end_date 
            FROM   cte c2 
                   CROSS JOIN (SELECT 1 AS n 
                               UNION 
                               SELECT 2 AS n) t 
            WHERE  md > 0) t1 
            order by start_date
    

    Online Demo

    输出

    +------------+------------+
    | start_date | end_date   |
    +------------+------------+
    | 2018-04-03 | 2018-04-17 |
    +------------+------------+
    | 2018-04-20 | 2018-04-20 |
    +------------+------------+
    | 2018-04-30 | 2018-04-30 |
    +------------+------------+
    | 2018-05-01 | 2018-05-04 |
    +------------+------------+
    | 2018-05-10 | 2018-05-27 |
    +------------+------------+
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-04
      • 2021-10-25
      • 1970-01-01
      • 2022-01-15
      • 1970-01-01
      • 1970-01-01
      • 2017-08-05
      • 1970-01-01
      相关资源
      最近更新 更多