【问题标题】:SQL breakout date range to rowsSQL 突破日期范围到行
【发布时间】:2015-06-10 06:25:48
【问题描述】:

我正在尝试获取在数据集中找到的给定日期范围,并将它们划分为该范围内每一天的唯一行(示例如下)。在SQL 中执行相反的操作非常简单,但我正在努力实现所需的查询输出。

开始数据:

ITEM    START_DATE  END_DATE
A       1/1/2015    1/5/2015
B       2/5/2015    2/7/2015

所需的查询输出:

 ITEM   DATE_COVERED
 A      1/1/2015
 A      1/2/2015
 A      1/3/2015
 A      1/4/2015
 A      1/5/2015
 B      2/5/2015
 B      2/6/2015
 B      2/7/2015

【问题讨论】:

标签: sql sql-server sql-server-2012 date-range


【解决方案1】:

最快的方法是一些计数表:

DECLARE @t TABLE
    (
      ITEM CHAR(1) ,
      START_DATE DATE ,
      END_DATE DATE
    )
INSERT  INTO @t
VALUES  ( 'A', '1/1/2015', '1/5/2015' ),
        ( 'B', '2/5/2015', '2/7/2015' )



;WITH cte AS(SELECT -1 + ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) d FROM
(VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) t1(n) CROSS JOIN
(VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) t2(n) CROSS JOIN
(VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) t3(n) CROSS JOIN
(VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) t4(n))

SELECT t.ITEM, ca.DATE_COVERED FROM @t t
CROSS APPLY(SELECT DATEADD(dd, d, t.START_DATE) AS DATE_COVERED 
            FROM cte 
            WHERE DATEADD(dd, d, t.START_DATE) BETWEEN t.START_DATE AND t.END_DATE) ca   
ORDER BY t.ITEM, ca.DATE_COVERED

【讨论】:

  • 当日期差很长时如何预测交叉连接添加与 CTE。like ('A', '1/1/1965', '1/5/2015')跨度>
  • @VinitPatel,只需添加更多交叉连接以确保它涵盖所有范围,但我怀疑他是否需要超过 5 个交叉连接,因为 5 个连接将涵盖 275 年。 6加入2732年。
【解决方案2】:

查询:

SQLFiddleExample

SELECT t.ITEM, 
        DATEADD(day,n.number, t.START_DATE) AS DATE_COVERED
FROM Table1 t,
(SELECT number
FROM master..spt_values
WHERE [type] = 'P') n
WHERE START_DATE <= DATEADD(day,n.number, t.START_DATE)
AND END_DATE >= DATEADD(day,n.number, t.START_DATE)

结果:

| ITEM | DATE_COVERED |
|------|--------------|
|    A |   2015-01-01 |
|    A |   2015-01-02 |
|    A |   2015-01-03 |
|    A |   2015-01-04 |
|    A |   2015-01-05 |
|    B |   2015-02-05 |
|    B |   2015-02-06 |
|    B |   2015-02-07 |

【讨论】:

    【解决方案3】:

    注意:这仅在您的 startdate 和 enddate 之间的差异最大为 2047 天时才有效(master..spt_values 只允许 0..2047 范围的值)

     select item, dateadd(d,v.number,d.start_date) adate
     from begindata d
     join master..spt_values v on v.type='P'
               and v.number between 0 and datediff(d, start_date, end_date)
     order by adate;
    

    我想说这是我自己做的,但我从this得到了代码

    这是你所期望的result的小提琴

    【讨论】:

    • 在您的代码中存在限制,最多可记录 2048 条,不再有记录......
    • 我刚刚检查了我的小提琴并得到了 2053 的结果集,之后我通过将两个开始日期都更改为 2000 年做了一个 4096 结果,所以我真的不知道你的意思@VinitPatel
    • ITEM START_DATE END_DATE A 1/1/1985 1/5/2015 试试这个并告诉我@Jeremy C.
    • @VinitPatel 哦,我明白你的意思是最大 2048 的日期范围,让我看看我是否可以解决这个问题
    • 我忘记了 master..spt_values 上的 0..2047 范围
    【解决方案4】:

    试试这个...

    CREATE TABLE Table1
        ([ITEM] varchar(1), [START_DATE] date, [END_DATE] date)
    ;
    
    INSERT INTO Table1
        ([ITEM], [START_DATE], [END_DATE])
    VALUES    ('A', '2015-01-01', '2015-01-05'), ('B', '2015-02-05', 2015-02-07');
    
    WITH    Days
              AS ( SELECT ITEM,  START_DATE AS [Date], 1 AS [level] from Table1
                   UNION ALL
                   SELECT  TABLE1.ITEM, DATEADD(DAY, 1, [Date]), [level] + 1
                   FROM     Days,Table1
                   WHERE  DAYS.ITEM=TABLE1.ITEM AND  [Date] < END_DATE )
         SELECT distinct [Date]
         FROM   Days
    

    DEMO

    【讨论】:

      猜你喜欢
      • 2013-03-06
      • 1970-01-01
      • 1970-01-01
      • 2011-02-12
      • 1970-01-01
      • 2016-10-25
      • 1970-01-01
      • 1970-01-01
      • 2017-12-20
      相关资源
      最近更新 更多