【问题标题】:How to Select continuous date in sql如何在sql中选择连续日期
【发布时间】:2017-08-24 00:45:50
【问题描述】:

是否有任何功能可以检查连续日期。我在处理以下问题时遇到问题:

我的表有一个 datetime 列,其中包含以下数据:

----------
2015-03-11
2015-03-12
2015-03-13
2015-03-16

给定开始日期为2015-3-11,结束日期为2015-3-17。我希望结果为:

----------
2015-03-11
2015-03-12
2015-03-13

任何人都可以提出任何建议吗?

【问题讨论】:

  • 你的字段是什么类型的?
  • 我刚刚在结束日期编辑了我的问题。现在您可以看到我现在无法应用 in 或 between 选项。
  • 如果数据中没有2015-03-11怎么办?并且跳过一天,但接下来的两三个日期是连续的?
  • 您使用哪个版本的 MSSQL?
  • 它只会从给定的开始日期开始,如果从开始日期没有连续的值,那么它可能会显示为空。但它不会采用任何不是从开始日期开始的连续值。及其 sql 2005

标签: sql sql-server


【解决方案1】:

我认为这在某种程度上是 Grouping Islands of Contiguous Dates 问题的变体。这可以使用ROW_NUMBER()

SQL Fiddle

CREATE TABLE Test(
    tDate   DATETIME
)
INSERT INTO Test VALUES
('20150311'), ('20150312'), ('20150313'), ('20150316');

DECLARE @startDate  DATE = '20150311'
DECLARE @endDate    DATE = '20150317'

;WITH Cte AS(
    SELECT
        *,
        RN = DATEADD(DD, - (ROW_NUMBER() OVER(ORDER BY tDATE) - 1), tDate)
    FROM Test
    WHERE 
        tDate >= @startDate
        AND tDate < DATEADD(DAY, 1, @endDate)
)
SELECT CAST(tDate AS DATE)
FROM CTE
WHERE RN = @startDate

结果

|------------|
| 2015-03-11 |
| 2015-03-12 |
| 2015-03-13 |

这是 SQL Server 2005 版本:

SQL Fiddle

DECLARE @startDate  DATETIME
DECLARE @endDate    DATETIME

SET @startDate  = '20150311'
SET @endDate    = '20150317'

;WITH Cte AS(
    SELECT
        *,
        RN = DATEADD(DD, -(ROW_NUMBER() OVER(ORDER BY tDATE)-1), tDate)
    FROM Test
    WHERE 
        tDate >= @startDate
        AND tDate < DATEADD(DAY, 1, @endDate)
)
SELECT CONVERT(VARCHAR(10), tDate, 121)
FROM CTE
WHERE RN = @startDate

【讨论】:

  • 在您的代码中一切正常。但对于结束日期,它似乎有一些问题。就像如果开始日期是 '20150311' 而结束日期是 '20150312' 那么它会显示结果 2015-03-11 2015-03-12 2015-03-13 。但应该是 2015-03-11 2015-03-12
  • 哦,对不起。它应该是 tdate &lt; DATEADD(DAY, 1, @endDate) 而不是 @endDate &lt; DATEADD(DAY, 1, @endDate)。查看我的编辑。
  • @GinUchiha,没问题。我可以帮忙。
【解决方案2】:

对于MSSQL 2012。这将返回 MAX 个连续组:

DECLARE @t TABLE(d DATE)

INSERT INTO @t VALUES
('20150311'),
('20150312'),
('20150313'),
('20150316')


;WITH
c1 AS(SELECT d, IIF(DATEDIFF(dd,LAG(d, 1, DATEADD(dd, -1, d)) OVER(ORDER BY d), d) = 1, 0, 1) AS n FROM @t),
c2 AS(SELECT d, SUM(n) OVER(ORDER BY d) AS n FROM c1) 

SELECT TOP 1 WITH TIES MIN(d) AS StartDate, MAX(d) AS EndDate, COUNT(*) AS DayCount
FROM c2
GROUP BY n
ORDER BY DayCount desc

输出:

StartDate   EndDate     DayCount
2015-03-11  2015-03-13  3

对于

('20150311'),
('20150312'),
('20150313'),
('20150316'),
('20150317'),
('20150318'),
('20150319'),
('20150320')

输出:

StartDate   EndDate     DayCount
2015-03-16  2015-03-20  5

c1 CTE中应用过滤:

c1 AS(SELECT d, IIF(DATEDIFF(dd,LAG(d, 1, DATEADD(dd, -1, d)) OVER(ORDER BY d), d) = 1, 0, 1) AS n FROM @t WHERE d BETWEEN '20150311' AND '20150320'),

对于MSSQL 2008

;WITH
c1 AS(SELECT d, (SELECT MAX(d) FROM @t it WHERE it.d < ot.d) AS pd FROM @t ot),
c2 AS(SELECT d, CASE WHEN DATEDIFF(dd,ISNULL(pd, DATEADD(dd, -1, d)),  d) = 1 THEN  0 ELSE 1 END AS n FROM c1),
c3 AS(SELECT d, (SELECT SUM(n) FROM c2 ci WHERE ci.d <= co.d)  AS n FROM c2 co) 

SELECT TOP 1 WITH TIES MIN(d) AS StartDate, MAX(d) AS EndDate, COUNT(*) AS DayCount
FROM c3
GROUP BY n
ORDER BY DayCount desc

【讨论】:

    【解决方案3】:

    您不需要像其他答案所说的那样声明任何开始日期或结束日期,您需要一个 row_numdatediff 函数:

    create table DateFragTest (cDate date);
    insert into DateFragTest 
           values ('2015-3-11'),
                  ('2015-3-12'),
                  ('2015-3-13'),
                  ('2015-3-16')
    
       with cte as 
          (select 
            cDate,
            row_number() over (order by cDate ) as rn
           from
            DateFragTest)
        select cDate 
        from cte t1  
        where datediff(day,
                       (select cDate from cte t2 where t2.rn=t1.rn+1),
                       t1.cDate)<>1
    

    输出:

    cDate
    2015-03-11
    2015-03-12
    2015-03-13
    

    SQLFIDDLE DEMO

    【讨论】:

      【解决方案4】:

      对于sql server 2012-

      WITH cte
      AS
      (
          SELECT [datex]
          ,      lead([datex]) OVER ( ORDER BY [datex]) lead_datex
          ,      datediff(dd,[datex],lead([datex]) OVER ( ORDER BY [datex]) ) AS diff
          FROM [dbo].[datex]
      )
      SELECT c.[datex]
      FROM [cte] AS c
      WHERE diff >=1
      

      【讨论】:

        【解决方案5】:

        使用BETWEEN

        查询将如下所示:

        SELECT * 
        FROM your_table_name
        WHERE your_date_column_name BETWEEN '2015-3-11' AND '2015-3-13'
        

        【讨论】:

          【解决方案6】:

          (dt between x and y) 或只是(dt &gt;= x and dt &lt;= y)

          【讨论】:

            猜你喜欢
            • 2019-08-10
            • 1970-01-01
            • 2021-08-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-07-10
            • 2021-12-06
            相关资源
            最近更新 更多