2016-06-22 155 views
0

我想爲我的問題找到合適的標題,到目前爲止它已經嘗試了30分鐘... :) 到目前爲止,我有以下示例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. 對於第一線,我們得到的是我們有0.125 $ /月($ 1/8月)
  2. 對於2號線,我們得到的是我們有$ 0.25 /月(3 $/12月)
  3. 對於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,而另外一組應該在那裏覆蓋重疊範圍2015/08/01 - 2015/08/31 :) 我會嘗試從這裏採取你的方法來達到結果:) 再次感謝您的即時響應! –

+0

我不明白你。我的腳本返回三個組。完全如您的要求。 –

+0

我很抱歉斯拉瓦!這是我的錯,它像你說的那樣運行! :) –