2016-11-11 14 views
0

年の最後の日付である年間売上に関する情報を含む表があります。年表の非正規化

endOfYearDate | metric1 | ... | metricN 

私は、その行のデータは、その年のために元の行から来ると、今年の毎日のための1行を持つように、このテーブルを非正規化したい:だからスキーマは次のようになります。したがって、指標はすべて重複しますが、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

ありがとうジョンこれは私が自分のコメントで行っていたことです、あなたの集計テーブルは私の個人的なラップトップで約9秒かかった何百万にもかかわらず、あなたの+1ので、動作します。あなたの集計を制限し、dayofyearをオフに働くことは、それをもう少しリーンにするでしょう – Matt

+0

@Matt 9秒! 0.307と0.378 –

+0

の間に私のラップトップえええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええないのは、私はi5、8GBのRAM、SSDは1秒あたり1GBの書き込みを読んでいます – Matt

1

、あなたはその後に参加するDATEPART(DAYOFYEAR、endOfYearDate)を使用することができる1とNの間の各整数の行を含むテーブル。タリー表は実際にはうるう年の366の値しか持たないことに注意してください。また、このメソッドを使用することは実際にはうるう年でも機能します。私はここに戻ったがDAYOFYEARを使用して代わりの日付のすべてを生成することによって、来る前に@ジョンは、基本的に私が書きたかったものを具現化

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 

は、集計テーブルがかなり小さいことを意味し、はるかに高速実行します。

日付ディメンションまで。私と他の多くの人が実際に作業する日付表を具体化します。たくさんの結合などを簡単にします。もしあなたがしなければならないことは、あなたが望む結果を得るための内部結合です。 Microsoft SSASはあなたのためのものを生成するか、独自のスクリプトを作成してビルドすることができます。

ここで、再帰的なcteを行う方法の1つです。あなたは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) 
関連する問題