![](/img/trans.png)
[英]SQL how to convert row with date range to many rows with date range with gaps based on a data column
[英]SQL how to convert row with date range to many rows with each date
如果我有一个看起来像这样的表
begin date end date data
2013-01-01 2013-01-04 7
2013-01-05 2013-01-06 9
如何让它像这样返回......
date data
2013-01-01 7
2013-01-02 7
2013-01-03 7
2013-01-04 7
2013-01-05 9
2013-01-06 9
我想做的一件事是让另一个表只包含所有日期,然后使用date>=begin date
和date<=end date
加入表中只有日期到上表,但这似乎有点笨拙除了重复日期之外,只保留额外的表格。
在某些情况下,我没有数据范围,只是一个as of
日期,基本上看起来像我的第一个例子,但没有end date
。 end date
由下一行的“ end date
暗示(即结束日期应as of
-1的下一行)。 我有一个“解决方案”,它使用row_number()函数来获取下一个值,但我怀疑这种方法,我正在做的方式有一堆嵌套的自联接,这导致非常长的查询时间。
使用一些样本数据......
create table data (begindate datetime, enddate datetime, data int);
insert data select
'20130101', '20130104', 7 union all select
'20130105', '20130106', 9;
查询 :(注意:如果你已经有一个数字/计数表 - 使用它)
select dateadd(d,v.number,d.begindate) adate, data
from data d
join master..spt_values v on v.type='P'
and v.number between 0 and datediff(d, begindate, enddate)
order by adate;
结果 :
| COLUMN_0 | DATA |
-----------------------------------------
| January, 01 2013 00:00:00+0000 | 7 |
| January, 02 2013 00:00:00+0000 | 7 |
| January, 03 2013 00:00:00+0000 | 7 |
| January, 04 2013 00:00:00+0000 | 7 |
| January, 05 2013 00:00:00+0000 | 9 |
| January, 06 2013 00:00:00+0000 | 9 |
或者,您可以动态生成数字表(0-99)或根据需要生成多个数字
;WITH Numbers(number) AS (
select top(100) row_number() over (order by (select 0))-1
from sys.columns a
cross join sys.columns b
cross join sys.columns c
cross join sys.columns d
)
select dateadd(d,v.number,d.begindate) adate, data
from data d
join Numbers v on v.number between 0 and datediff(d, begindate, enddate)
order by adate;
您可以使用递归CTE来获取两个日期之间的所有日期。 另一个CTE是让ROW_NUMBERs帮助你找到那些缺少EndDates的人。
DECLARE @startDate DATE
DECLARE @endDate DATE
SELECT @startDate = MIN(begindate) FROM Table1
SELECT @endDate = MAX(enddate) FROM Table1
;WITH CTE_Dates AS
(
SELECT @startDate AS DT
UNION ALL
SELECT DATEADD(DD, 1, DT)
FROM CTE_Dates
WHERE DATEADD(DD, 1, DT) <= @endDate
)
,CTE_Data AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY BeginDate) AS RN FROM Table1
)
SELECT DT, t1.data FROM CTE_Dates d
LEFT JOIN CTE_Data t1 on d.DT
BETWEEN t1.[BeginDate] AND COALESCE(t1.EndDate,
(SELECT DATEADD(DD,-1,t2.BeginDate) FROM CTE_Data t2 WHERE t1.RN + 1 = t2.RN))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.