SQL:GROUP BY之后的SUM

时间:2013-10-11 16:48:29

标签: sql group-by sum

样本表

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提供多行...

我计算了凭证所涵盖的月份为DATEDIFF(MM,StartDate,EndDate)+ 1 ...

当我应用SUM(DATEDIFF(MM,StartDate,EndDate))GROUP BY VoucherId,StartDate,EndDate时 由于VoucherId ....的多行,我给出了错误的结果。

我得到这样的东西......

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

在这种情况下,CategoryId无用

由于

4 个答案:

答案 0 :(得分:4)

实际上,在您的情况下(当每个类别的句点相等时),您可以使用此查询:

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

答案 1 :(得分:0)

您在查询中按不需要的列进行分组。

SQLFiddle!

答案 2 :(得分: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

这假设您在第一个开始日期和最后结束日期之间没有间隙。如果这样做,您可能需要编辑内部选择。但我们的想法是让内部选择确定你的日期范围(并忽略类别),然后让外部选择总结几个月。

答案 3 :(得分:0)

<强> sql fiddle demo

这个SQL小提琴解决了您的顾虑。您需要生成一个日历表,以便您有一些东西可以加入您的日期。然后,您可以为每个客户计算不同的MonthYears。

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