我有一张表格,其中包含有关年度销售额的信息,其中日期是一年中的最后一个日期。架构如下所示:
endOfYearDate | metric1 | ... | metricN
我想对此表进行非规范化,使一年中的每一天都有一行,该行的数据来自该年的原始行。因此,指标都会重复,但date
会有所不同。
dailyDate | metric1 | ... | metricN
是否有SQL查询可以轻松完成此操作?
答案 0 :(得分:1)
Declare @YourTable table (endOfYearDate date,metric1 int,metric2 int)
Insert Into @YourTable values
('2014-12-31',10,25),
('2015-12-31',35,50),
('2016-12-31',200,250)
;with cteMinMax As (
Select MinDate=DateAdd(YY,-1,min(endOfYearDate))
,MaxDate=DateAdd(YY, 1,max(endOfYearDate))
,Days =DateDiff(DD,DateAdd(YY,-1,min(endOfYearDate)),DateAdd(YY, 1,max(endOfYearDate)))
From @YourTable
)
,cte0(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N))
,cteD(D) As (Select Top (Select Days from cteMinMax) cast(DateAdd(DD,Row_Number() over (Order By (Select NULL)),(Select MinDate from cteMinMax)) as date) From cte0 N1, cte0 N2, cte0 N3, cte0 N4, cte0 N5, cte0 N6)
Select Date=D
,B.*
From cteD A
Join @YourTable B on Year(endOfYearDate)=Year(D)
Order By D
返回
答案 1 :(得分:1)
使用Tally Table,一个表格,其中包含1到N之间的每个整数的行,然后您可以使用DATEPART(dayofyear,endOfYearDate)加入。请注意,计数表实际上只需要有366个闰年值。使用这种方法实际上也适用于闰年。
Declare @YourTable table (endOfYearDate date,metric1 int,metric2 int)
Insert Into @YourTable values
('2014-12-31',10,25),
('2015-12-31',35,50),
('2016-12-31',200,250)
;WITH cte AS (Select 1 as N From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N))
,cteTally AS (
SELECT Number = ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM
cte n
CROSS JOIN cte n2
CROSS JOIN cte n3
)
SELECT
DATEADD(day,- t.Number + 1, yt.endOfYearDate) as Date
,yt.endOfYearDate
,yt.metric1
,yt.metric2
FROM
@YourTable yt
INNER JOIN cteTally t
ON DATEPART(dayofyear,yt.endOfYearDate) >= t.Number
ORDER BY
Date
@John在我回到这里之前基本上体现了我想写的东西,但是通过使用DAYOFYEAR而不是生成所有日期意味着计数表明显更小并且执行速度更快。
至于Date Dimmension。我和其他许多人实际上实现了一个日期表来使用它会使很多连接变得更容易,如果你有一个你需要做的就是内部连接来获得你想要的结果。 Microsoft SSAS将为您生成一个,或者您可以构建一个脚本来构建自己的脚本。
这是一种做递归cte的方法。你会注意到我必须将递归的最大级别设置为365(366 - 1)。
;WITH cteRecursive AS (
SELECT endOfYearDate as Date, DATEPART(dayofyear,endOfYearDate) as DOY, endOfYearDate, metric1, metric2
FROM
@YourTable
UNION ALL
SELECT
DATEADD(day,-1,Date)
,DOY - 1
,endOfYearDate
,metric1
,metric2
FROM
cteRecursive
WHERE
DOY - 1 > 0
)
SELECT Date, endOfYearDate, metric1, metric2
FROM
cteRecursive
ORDER BY
Date
OPTION (maxrecursion 365)