2016-11-11 159 views
0

我有一張表,其中包含有關年銷售額的信息,其中日期是一年中的最後一個日期。因此,該模式是這樣的:非規範化年度表

endOfYearDate | metric1 | ... | metricN 

我想非規範化此表有一行一年的每一天,該行從原來的行當年來的數據。所以度量將全部重複,但date將會不同。

dailyDate | metric1 | ... | metricN 

是否有SQL查詢可以輕鬆完成此操作?

+0

請問您能解釋一下嗎? – user1742188

回答

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 

返回

enter image description here

+0

感謝John,這是我在評論中所要表達的意思,你的作品是+1,儘管因爲你的理貨表進入了數百萬人,所以在我的個人筆記本電腦上花費了大約9秒。限制你的計數並在一天之內工作會使它更瘦一點 – Matt

+0

@Matt 9秒!我的筆記本電腦在0.307和0.378之間 –

+0

是第一次運行後的執行時間爲9秒,其中由於緩存的執行計劃而少於一秒。我在i5,8GB內存上,讀取SSD的速度接近每秒1 GB – Matt

1

使用帳簿表,與行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 

@約翰基本上體現了我想寫我就回來了,但是通過使用DAYOFYEAR,而不是生成所有日期的前指理貨表是顯著更小,執行速度快了很多。

只要一個日期dimmension。我和許多其他人實際上實現了一個日期表來處理它,使得大量的連接等變得更加容易,如果你有一個你只需要一個內部連接來獲得你想要的結果。微軟SSAS將爲您生成一個,或者您可以構建一個腳本來構建自己的腳本。

這裏是做遞歸的一種方法。你會注意到我必須將遞歸的最大級別設置爲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)