创建一个查询以汇总3个月,6个月的总计

时间:2016-03-11 18:45:45

标签: sql sql-server sql-server-2008-r2 aggregation

我正在使用SQL Server 2008 R2。我正在尝试创建一个按3M,6M,9M,12M总计汇总总计的查询。以下是一些示例数据:

create table invoice (store int, invoice_date datetime, customer int, is_repeat varchar(1));

insert into invoice (store, invoice_date, customer, is_repeat)
values (1, '2015-10-05', 1, 'N'),
(1, '2016-03-04', 1, 'Y'),
(1, '2016-02-07', 1, 'Y'),
(1, '2015-08-03', 2, 'Y'),
(2, '2015-12-01', 3, 'Y'),
(2, '2016-02-16', 4, 'Y'),
(2, '2015-06-11', 3, 'Y'),
(2, '2015-09-18', 4, 'Y');

查询需要提供3M,6M等数量的' Y'值,按商店,月份和年份汇总。例如,2016年3月的商店1应该有一个记录,总数为' Y'在2015年12月1日和2016年2月29日之间的值,并将该值放在3M列中。然后将9/1/2015和02/29/2016之间的值相加,并将这些值放在6M列中。

以下是上述数据的查询结果示例:

STORE     MONTH     YEAR     3M_REPEATS     6M_REPEATS
-----     -----     ----     ----------     ----------
  1         2       2016         0              2
  1         3       2016         1              2
  2         2       2016         1              3
  2         3       2016         2              3

我试图找到一个优雅的解决方案,但我不确定我是应该使用CTE,PIVOT还是OVER(PARTITION BY),还是仅使用标准的GROUP BY子句。

编辑添加:我最终只需要这个表中的最后12个月,因此此表中只有12条记录。例如,如果当前月/年为2016年3月,它将具有2/2015 - 3/2016以及每月的总计。

3 个答案:

答案 0 :(得分:1)

通过使用案例陈述来获取每个季度的记录,然后使用分组

select 
store,
datepart(m, invoice_date) as mth,
datepart(yyyy, invoice_date) as yr,
Sum(case when datename(qq,invoice_date)=1 then 1 else 0 end) as QTR1, 
Sum(case when datename(qq,invoice_date)=2 6 then 1 else 0 end) as QTR2
FROM test 
WHERE is_repeat='Y'
GROUP BY store, datepart(m, t.invoice_date), datepart(yyyy, t.invoice_date)
ORDER BY store, mth, yr

答案 1 :(得分:0)

我会为聚合和GROUP BY Store,Month,Year提供SUM CASE表达式。

答案 2 :(得分:0)

这是一个使用分析函数的版本:

with agg as (
    select
        store,
        min(invoice_date) as invoice_month,
        count(case when is_repeat = 'Y' then 1 end) as y_count 
    from invoice
    where 
            invoice_date >= dateadd(month, -14, current_timestamp)
        and datediff(month, invoice_date, current_timestamp) between 1 and 12 
    group by
        store,
        datediff(month, invoice_date, current_timestamp)
)
select
    store,
    datepart(month, a1.invoice_month) as "month",
    datepart(year, a1.invoice_month) as "year",
    sum(y_count) over (
        partition by store
        order by invoice_month
        rows between 2 preceding and current row
    ) as 3m_repeats,
    sum(y_count) over (
        partition by store
        order by invoice_month
        rows between 5 preceding and current row
    ) as 6m_repeats
from agg

但是,由于你不能在2008年使用rows between,我认为这可以替代:

with agg as (
    select
        store,
        min(invoice_date) as invoice_month,
        count(case when is_repeat = 'Y' then 1 end) as y_count 
    from invoice
    where 
            invoice_date >= dateadd(month, -14, current_timestamp)
        and datediff(month, invoice_date, current_timestamp) between 1 and 12 
    group by
        store,
        datediff(month, invoice_date, current_timestamp)
)
select
    store,
    datepart(month, a1.invoice_month) as "month",
    datepart(year, a1.invoice_month) as "year",
    sum(case
        when datediff(month, a1.invoice_date, a2.invoice_date)
            between -2 and 0
        then y_count end
    ) as 3m_repeats,
    sum(case
        when datediff(month, a1.invoice_date, a2.invoice_date)
            between -5 and 0 then y_count end
    ) as 6m_repeats,
from agg a1 inner join agg a2
    on      a2.store = a1.store
        and datediff(month, a1.invoice_date, a2.invoice_date) between -5 and 0
group by a1.store, a1.invoice_month

我假设你有所有月份的数据,所以我没有打扰这个并发症。