2016-06-22 6 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. Для трехмерной линии мы получаем, что у нас есть 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

Прошу прощения, Слава! Это была моя ошибка, она работает, как вы сказали! :) –

Смежные вопросы