改进此查询(按行划分的过去销售总额)

时间:2017-08-01 13:34:29

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

我正在尝试改进此查询。它来自一个更大的桌子,但我已经采取了必需品,并将其削减到下面的问题。此表为我们提供了特定月份,商店和产品组的销售额。对于每一行(即月/商店/产品组合),我需要在此之前的前两个和四个月的销售总额。

我所提供的内容在提供正确的值方面效果很好,但它在大型桌面上是一种性能损失。我查看了具有PRECEDING / FOLLOWING约束的OVER子句,但我使用的SQL Server 2008不支持这些。您是否看到了更优化的方法来重写它并给出相同的期望结果?谢谢。

create table #sales_by_month 
(
    period int, --YYYYMM
    store varchar(8), --store number
    product_group varchar(8),
    sales int
)

insert into #sales_by_month values (201701, 51, 'shoes', 12)
insert into #sales_by_month values (201701, 51, 'clothes', 15)
insert into #sales_by_month values (201701, 12, 'shoes', 10)
insert into #sales_by_month values (201701, 12, 'clothes', 9)
insert into #sales_by_month values (201702, 51, 'shoes', 0)
insert into #sales_by_month values (201702, 51, 'clothes', 20)
insert into #sales_by_month values (201702, 12, 'shoes', 30)
insert into #sales_by_month values (201702, 12, 'clothes', 8)
insert into #sales_by_month values (201703, 51, 'shoes', 7)
insert into #sales_by_month values (201703, 51, 'clothes', 4)
insert into #sales_by_month values (201703, 12, 'shoes', 21)
insert into #sales_by_month values (201703, 12, 'clothes', 0)
insert into #sales_by_month values (201704, 51, 'shoes', 50)
insert into #sales_by_month values (201704, 51, 'clothes', 4)
insert into #sales_by_month values (201704, 12, 'shoes', 16)
insert into #sales_by_month values (201704, 12, 'clothes', 20)
insert into #sales_by_month values (201705, 51, 'shoes', 21)
insert into #sales_by_month values (201705, 51, 'clothes', 17)
insert into #sales_by_month values (201705, 12, 'shoes', 0)
insert into #sales_by_month values (201705, 12, 'clothes', 5)

select 
    period, 
    store, 
    product_group, 
    (select sum(sales) 
     from #sales_by_month x2 
     where x2.store = #sales_by_month.store 
       and x2.product_group = #sales_by_month.product_group 
       and left(x2.period, 4) * 12 + right(x2.period, 2) 
                between left(#sales_by_month.period, 4) * 12 + right(#sales_by_month.period, 2) - 1
                    and left(#sales_by_month.period, 4) * 12 + right(#sales_by_month.period, 2) ) sales_to_date_last_2_months,
    (select sum(sales) 
     from #sales_by_month x4
     where x4.store = #sales_by_month.store 
       and x4.product_group = #sales_by_month.product_group 
       and left(x4.period, 4) * 12 + right(x4.period, 2) 
               between left(#sales_by_month.period, 4) * 12 + right(#sales_by_month.period, 2) - 3
                   and left(#sales_by_month.period, 4) * 12 + right(#sales_by_month.period, 2)) sales_to_date_last_4_months
from 
    #sales_by_month

--drop table #sales_by_month 

2 个答案:

答案 0 :(得分:1)

您可以在SQL Server 2012中使用带有sum()的窗口子句。假设您拥有每个月的数据并存储

select sbm.*,
       sum(sales) over (partition by store, productgroup 
                        order by period
                        rows between 4 preceding and 2 preceding
                       ) as sales_2_4
from #sales_by_month sbm;

这在SQL Server 2008中不起作用。我建议apply

with sbm as (
      select sbm.*,
              row_number() over (partition by store, productgroup order by period) as seqnum
      from #sales_by_month sbm
     )
select sbm.*, sbm2.sales_2_4
from sbm outer apply
     (select sum(sbm2.sales) as sales_2_4
      from sbm sbm2
      where sbm2.store = sbm.store and sbm2.productgroup = sbm2.productgroup and
            sbm2.seqnum between sbm.seqnum - 4 and sbm.seqnum - 2
     ) sbm2

答案 1 :(得分:0)

试试这个:

    SELECT CONVERT(DATE,SUBSTRING(CONVERT(NVARCHAR,period),1,4) +'-'+ SUBSTRING(CONVERT(NVARCHAR,period),5,2) + N'-01')periodDt 
,DATEADD(MONTH,2,CONVERT(DATE,SUBSTRING(CONVERT(NVARCHAR,period),1,4) +'-'+ SUBSTRING(CONVERT(NVARCHAR,period),5,2) + N'-01'))periodDt2 
,DATEADD(MONTH,4,CONVERT(DATE,SUBSTRING(CONVERT(NVARCHAR,period),1,4) +'-'+ SUBSTRING(CONVERT(NVARCHAR,period),5,2) + N'-01'))periodDt4 
,* INTO #t1 FROM #sales_by_month 

SELECT periodDt,periodDt2,periodDt4,period,store,product_group, SUM(sales)sales INTO #t2 FROM #t1 GROUP BY periodDt,periodDt2,periodDt4,period,store,product_group

SELECT ISNULL([2m].store,[4m].store),ISNULL([2m].product_group,[4m].product_group),ISNULL(sales2month,0),ISNULL(sales4month,0)  FROM 
(SELECT store,product_group,sales sales2month FROM #t2 WHERE perioddt2 >= GETDATE())[2m]
FULL JOIN 
(SELECT store,product_group,sales sales4month FROM #t2 WHERE perioddt4 >= GETDATE())[4m]
ON [2m].store = [4m].store AND [2m].product_group = [4m].product_group