2016-06-22 6 views
0

Ich versuche einen passenden Titel für meine Frage zu finden und bisher waren es 30 Minuten Versuche ... :) Bis jetzt habe ich das folgende BeispielSQL: Erstelle neue Gruppen von Datumsbereichen aus einer Reihe von Datumsbereichen

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. Für die erste Linie, die wir bekommen, dass wir 0.125 $/Monat ($ 1/8 Monate)
  2. Für die zweite Linie, die wir bekommen, dass wir 0,25 $/Monat ($ 3/12 haben Monate)
  3. Für die 3d Linie bekommen wir, dass wir 1,4 $/Monat (7 $/5 Monate)
  4. haben

Angesichts der oben genannten möchten wir eine neue Gruppe von Datumsbereichen erstellen, um die Summen der Beträge zu haben. Etwas wie die Ergebnisse unten:

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$ 

Die Summe der oben genannten ist 11 $ genau wie die ursprünglichen Daten. Das Ergebnis, das wir erzielen möchten, ist die Summe des Betrags pro eindeutiger Gruppe von Datumsbereichen.

Kann dies mit SQL erreicht werden?

Antwort

0

Lösung ist nicht sehr elegant und hat wahrscheinlich einige unnötigen Teile, aber es erzeugt richtiges Ergebnis:

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

dort Hallo! Danke für die Rückmeldung! CTE zu verwenden und die Bereiche in Monate zu brechen, ist ein netter Ansatz. Wir sollten jedoch die Bereiche berücksichtigen, die sich überschneiden, um die Beträge zu aggregieren. In Ihrem Fall, so weit ich das verstehe, zeigen die Ergebnisse zwei Gruppen: 2015/01/01 - 2015/07/31 und 2015/08/01 - 2015/12/31 während und zusätzliche Gruppe sollte dort sein, die die überlappende Bereiche für 2015/08/01 - 2015/08/31 :) Ich werde versuchen, es von hier aus mit Ihrem Ansatz zu einem Ergebnis zu erreichen :) Nochmals vielen Dank für die sofortige Antwort! –

+0

Ich verstehe dich nicht. Mein Skript gibt drei Gruppen zurück. Genau wie in Ihrer Anfrage. –

+0

Es tut mir leid, Slava! Es war mein Fehler, es läuft wie du gesagt hast! :) –