2016-06-22 22 views
0

私の質問の適切なタイトルを探していますが、これまでに30分試しています... :) これまでの例我々は、我々は0.25 $ /月(3 $/12を持っていることを取得する第二ラインについては0.125 $ /月(1 $/8ヶ月) SQL:日付範囲のセットから新しい範囲の日付範囲を作成する

  • を持っていることを取得する最初の行のために

    DateFrom DateTo Amount 
    2015/01/01 2015/08/31 1$ 
    2015/01/01 2015/12/31 3$ 
    2015/08/01 2015/12/31 7$ 
    
    1. 月)
    2. 3dラインの場合、1.4ドル/月(7ドル/ 5ヶ月)

    上記を考慮して、金額の合計を得るために日付範囲の新しいグループを作成したいと考えています。以下の結果のようなもの:

    DateFrom DateTo   Amount 
    2015/01/01 2015/07/31 (0.125$+0.25$)*7 =2.625$ 
    2015/08/01 2015/08/31 (1.4$+0.125$+0.25$)*1 =1.775$ 
    2015/09/01 2015/12/31 (1.4$+0.25$)*4 =6.6$ 
    

    上記の合計は元のデータと同じ11 $です。実際には、日付範囲の一意のグループあたりの金額の合計です。

    これはSQLで実現できますか?

  • 答えて

    0

    ソリューションは非常にエレガントではなく、おそらくいくつかの不要な部分を持っていますが、それは正しい結果生成しますが

    SELECT * INTO tbl_Periods 
    FROM (VALUES 
    ('2015/01/01','2015/08/31',1), 
    ('2015/01/01','2015/12/31',3), 
    ('2015/08/01','2015/12/31',7)) as x(DateFrom,DateTo,Amount); 
    GO 
    ;WITH 
        Pass0 as (select 1 as C union all select 1), 
        Pass1 as (select 1 as C from Pass0 as A, Pass0 as B), 
        Pass2 as (select 1 as C from Pass1 as A, Pass1 as B), 
        Pass3 as (select 1 as C from Pass2 as A, Pass2 as B) 
    , CTE1 as (
        SELECT *, Amount/DateDiff(MONTH, DateFrom, DATEADD(day, 1 ,DateTo)) as MRate 
        FROM tbl_Periods 
    ) 
    , CTEM as (SELECT MIN(DateFrom) as MinDate, DATEADD(day, 1, MAX(DateTo)) as MaxDate 
        , DateDiff(MONTH, MIN(DateFrom), DATEADD(day, 1, MAX(DateTo))) as NPeriods FROM tbl_Periods) 
    , CTEP as (
        SELECT TOP ((SELECT NPeriods FROM CTEM)) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) as RNumber 
        FROM Pass3 as p 
        ) 
    , PeriodList as (
        SELECT DateAdd(month, RNumber-1,MinDate) as PeriodStarts, DateAdd(month, RNumber,DATEADD(day,-1,MinDate)) as PeriodEnds 
        FROM CTEM as m CROSS JOIN CTEP as p) 
    , MPerriods as (
        SELECT * 
        FROM CTE1 as c 
        INNER JOIN PeriodList as l 
        ON l.PeriodStarts between c.DateFrom and c.DateTo) 
    , CPeriods as (
        SELECT PeriodStarts, PeriodEnds, SUM(MRate) as MRate 
         , RNK = RANK() OVER(ORDER BY PeriodStarts) 
          - RANK() OVER(PARTITION BY SUM(MRate) ORDER BY PeriodStarts) 
        FROM MPerriods 
        GROUP BY PeriodStarts, PeriodEnds 
    ) 
    SELECT MIN(PeriodStarts) as PeriodStarts, MAX(PeriodEnds) as PeriodEnds, COUNT(*) * MRate 
    FROM CPeriods 
    GROUP BY MRate, RNK 
    ORDER BY 1; 
    GO 
    

    enter image description here

    +0

    こんにちは! フィードバックいただきありがとうございます! CTEを使用し、範囲を数か月に分割するのは良いアプローチです。しかし、金額を集計するために重複する範囲を考慮する必要があります。あなたのケースでは、私が理解できる限り、結果には、 2015/01/01 - 2015/07/31と2015/08/01 - 2015/12/31という2つのグループが表示されますが、追加のグループは、 2015/08/01 - 2015/08/31のオーバーラップ範囲: あなたのアプローチを使用して結果に到達しようとしています: すぐにお返事ありがとうございました! –

    +0

    私はあなたを理解していません。私のスクリプトは3つのグループを返します。あなたの要求とまったく同じです。 –

    +0

    申し訳ありませんがスラヴァです!それは私の間違いだった、それはあなたが言ったように実行されます! :) –