2013-10-11 5 views
3

Образец таблицыSQL: SUM после GROUP BY

CustomerId | VoucherId | CategoryId | StartDate | EndDate 
------------------------------------------------------------- 
     10 |   1 |   1 | 2013-09-01| 2013-09-30 
     10 |   1 |   2 | 2013-09-01| 2013-09-30 
     11 |   2 |   1 | 2013-09-01| 2013-11-30 
     11 |   2 |   2 | 2013-09-01| 2013-11-30 
     11 |   2 |   3 | 2013-09-01| 2013-11-30 
     10 |   3 |   1 | 2013-10-01| 2013-12-31 
     10 |   3 |   2 | 2013-10-01| 2013-12-31 
     11 |   4 |   1 | 2013-12-01| 2014-04-30 

В вышеуказанной записи образца, я хочу узнать Общее количество месяцев ваучеры клиента покрывают

мне нужен выход в виде

CustomerId | Months 
-------------------- 
     10 | 4 
     11 | 8 

Загвоздка в том, что ваучер может иметь несколько строк для различных CategoryIds ...

I ча lculated месяцев охватываемые ваучер, как DATEDIFF (ММ, StartDate, EndDate) + 1 ...

Когда я применить SUM (DATEDIFF (ММ, StartDate, EndDate)) GROUP BY VoucherId, StartDate, EndDate Я даю неправильный результат из-за нескольких строк для VoucherId ....

я получаю что-то вроде этого ...

CustomerId | Months 
-------------------- 
     10 | 8 
     11 | 14 

CategoryId бесполезен в этом сценарии

Благодаря

ответ

0

sql fiddle demo

Этот SQL Скрипки адреса ваших проблем. Вам нужно сгенерировать таблицу календаря, чтобы у вас было что-то, чтобы присоединиться к вашим датам. Затем вы можете подсчитать количество месяцев в месяц для каждого Клиента.

create table test(
    CustomerId int, 
    StartDate date, 
    EndDate date 
) 

insert into test 
values 
    (10, '9/1/2013', '9/30/2013'), 
    (10, '9/1/2013', '9/30/2013'), 
    (11, '9/1/2013', '11/30/2013'), 
    (11, '9/1/2013', '11/30/2013'), 
    (11, '9/1/2013', '11/30/2013'), 
    (10, '10/1/2013', '12/31/2013'), 
    (10, '10/1/2013', '12/31/2013'), 
    (11, '12/1/2013', '4/30/2014') 

create table calendar(
    MY varchar(10), 
    StartDate date, 
    EndDate date 
) 

insert into calendar 
values 
    ('9/2013', '9/1/2013', '9/30/2013'), 
    ('10/2013', '10/1/2013', '10/31/2013'), 
    ('11/2013', '11/1/2013', '11/30/2013'), 
    ('12/2013', '12/1/2013', '12/31/2013'), 
    ('1/2014', '1/1/2014', '1/31/2014'), 
    ('2/2014', '2/1/2014', '2/28/2014'), 
    ('3/2014', '3/1/2014', '3/31/2014'), 
    ('4/2014', '4/1/2014', '4/30/2014') 

select 
    t.CustomerId, 
    count(distinct c.MY) 
from 
    test t 
    inner join calendar c 
    on t.StartDate <= c.EndDate 
     and t.EndDate >= c.StartDate 
group by 
    t.CustomerId 
+0

Спасибо ... Это работает ... Незначительный перебор, хотя :) –

+0

Если у вас есть возможность совпадения диапазонов дат, тогда это может быть необходимо. Скажем, клиентский 1 имеет диапазоны дат 9/1-10/4, 12/1-12/30, 10/1-11/30. Решение Романа дало бы вам сумму 5 (2 + 1 + 2), когда должно быть 4 (с сентября по декабрь = 4). –

0

Вы группируете ненужные столбцы в свой запрос.

SQLFiddle!

+0

Ответ не является правильным для запроса ... CustomerId | Месяцы -------------------- 10 | 4 11 | 10 Это потому, что вы не добавили 1 к функции DATEDIFF –

3

на самом деле, в вашем случае (когда периоды для каждой категории равны), вы можете использовать этот запрос:

with cte as (
    select distinct 
     CustomerId, StartDate, EndDate 
    from Table1 
) 
select CustomerId, sum(datediff(mm, StartDate, EndDate) + 1) as diff 
from cte 
group by CustomerId 

sql fiddle demo

+0

Спасибо ... Работала как шарм ... –

+0

и его элегантный –

+0

@MuhammadIbraheem спасибо :) –

0

Попробуйте это:

SELECT 
    T.CustomerId, 
    T.VoucherId, 
    SUM(DATEDIFF(MM, T1.FirstStartDate, T1.LastEndDate)) AS Months 
FROM #YourTable T 
JOIN 
(
    SELECT 
     CustomerId, 
     VoucherId, 
     MIN(StartDate) AS FirstStartDate, 
     MAX(EndDate) AS LastEndDate 
    FROM #YourTable T1 
    GROUP BY CustomerId, VoucherId 
) ON T.CustomerId = T1.CustomerId AND T.VoucherId = T1.VoucherId 

Предполагается, что у вас нет пробелов между первой датой начала и последней конечной датой. Если вы это сделаете, вам может потребоваться отредактировать внутренний выбор. Но идея состоит в том, чтобы внутренний выбор определял ваши диапазоны дат (и игнорировал категории), а затем внешняя составляла ваши месяцы.

+0

Спасибо ... получила идею ... хотя в моем случае промежутки между датами возможны ... –