1

我正在构建一个报告以显示产品级别的销售额,并且需要包括已售出每种产品的商店数量。我的销售数据按周细分,但我还需要包括每日级别的服务水平统计数据。

我遇到的问题是,当我尝试计算每种产品销售的商店数量时,它最多乘以 7 倍(取决于一周中有多少天有服务水平记录),所以我的问题是我能否在一个查询中获得不同数量的商店。

数据结构如下:

销售数据

WeekNo   StoreNo   ProductNo   SalesValue
201301   123       123456       10,000.00
201301   123       654321        5,000.00
201301   124       123456        9,400.00
201301   124       654321        3,500.00
201302   123       123456       11,500.00
etc.

服务水平数据 通过将日历日期转换为 WeekNo 的表连接到销售

Date         StoreNo   ProductNo   ServiceLevel
01/01/2013   123       123456                99
03/01/2013   123       123456                98
04/01/2013   123       123456               100
etc.

我的SQL如下:

 select sales.ProductNo,
        prod.ProductDesc,
        sum(case when sales.WeekNo = 201330 then 1 end) as StoresSoldInThisWeek,
        sum(case when sales.WeekNo = 201329 then 1 end) as StoresSoldInLastWeek,
        sum(case when sales.WeekNo between 201324 and 201327 then 1 end) / 4 as StoresSoldInAverage,
        sum(case when sales.WeekNo = 201330 then sales.SalesValue end) as SalesValueThisWeek,
        sum(case when sales.WeekNo = 201329 then sales.SalesValue end) as SalesValueLastWeek,
        sum(case when sales.WeekNo between 201324 and 201327 then wks.SalesValue end) / 4 as SalesValueAverage,
        sum(case when sales.WeekNo = 201330 then sales.SalesVolume end) as SalesVolumeThisWeek,
        sum(case when sales.WeekNo = 201329 then sales.SalesVolume end) as SalseVolumeLastWeek,
        sum(case when sales.WeekNo between 201324 and 201327 then sales.SalesVolume end) / 4 as SalesVolumeAverage,
        cast(sum(case when serv.WeekNo = 201330 then serv.Delivered end) as float) / nullifzero(cast(sum(case when serv.WeekNo = 201330 then serv.Ordered end) as float)) as ServiceLevelThisWeek,
        cast(sum(case when serv.WeekNo = 201329 then serv.Delivered end) as float) / nullifzero(cast(sum(case when serv.WeekNo = 201329 then serv.Ordered end) as float)) as ServiceLevelLastWeek,
        cast(sum(case when serv.WeekNo between 201324 and 201327 then serv.Delivered end) as float) / nullifzero(cast(sum(case when serv.WeekNo between 201324 and 201327 then serv.Ordered end) as float)) as ServiceLevelAverage

   from Products prod
        inner join Sales sales
                on prod.ProductNo = sales.ProductNo
               and sales.WeekNo in (201324,201325,201326,201327,201329,201330)
         left join ServiceLevel serv
                on sales.ProductNo = serv.ProductNo
               and sales.StoreNo = serv.StoreNo
         left join Weeks week
                on serv.CalDate between week.WeekStartDate and week.WeekEndDate
               and sales.WeekNo = week.WeekNo

group by 1,2

order by 1

我尝试获取每种产品销售的商店数量是:

sum(case when sales.WeekNo = 201302 then 1 end) as StoresSoldInThisWeek,
sum(case when sales.WeekNo = 201301 then 1 end) as StoresSoldInLastWeek,

我曾尝试将服务水平数据汇总为数周,但这会导致查询运行时间过长,所以我的问题是获得不同商店数量的最有效方法是什么?我怀疑这需要 ROW_NUMBER() 函数,但它似乎不喜欢我在 Group By 字段中这样做

4

1 回答 1

3

首先,我认为您当前的方法也无法计算其他列的正确值。例如,每个 SalesValue 将在每个 ServiceLevel 行汇总一次:

sum(case when sales.WeekNo = 201330 then sales.SalesValue end) as SalesValueThisWeek,

您需要在加入之前进行聚合,从而避免多次加入同一行。我就是这样做的(我不知道它是否真的符合您的需求):

select sales.ProductNo,
        prod.ProductDesc,
        sales.StoresSoldInThisWeek,
        sales.StoresSoldInLastWeek,
        sales.StoresSoldInAverage,
        sales.SalesValueThisWeek,
        sales.SalesValueLastWeek,
        sales.SalesValueAverage,
        sales.SalesVolumeThisWeek,
        sales.SalseVolumeLastWeek,
        sales.SalesVolumeAverage,
        serv.ServiceLevelThisWeek,
        serv.ServiceLevelLastWeek,
        serv.ServiceLevelAverage
   from Products prod
   inner join
    ( -- you only use columns from sales, so all the calculations can be done without joins
      select
         sales.ProductNo,
         sum(case when sales.WeekNo = 201330 then 1 end) as StoresSoldInThisWeek,
         sum(case when sales.WeekNo = 201329 then 1 end) as StoresSoldInLastWeek,
         sum(case when sales.WeekNo between 201324 and 201327 then 1 end) / 4 as StoresSoldInAverage,
         sum(case when sales.WeekNo = 201330 then sales.SalesValue end) as SalesValueThisWeek,
         sum(case when sales.WeekNo = 201329 then sales.SalesValue end) as SalesValueLastWeek,
         sum(case when sales.WeekNo between 201324 and 201327 then wks.SalesValue end) / 4 as SalesValueAverage,
         sum(case when sales.WeekNo = 201330 then sales.SalesVolume end) as SalesVolumeThisWeek,
         sum(case when sales.WeekNo = 201329 then sales.SalesVolume end) as SalseVolumeLastWeek,
         sum(case when sales.WeekNo between 201324 and 201327 then sales.SalesVolume end) / 4 as SalesVolumeAverage
      from Sales sales
      where sales.WeekNo in (201324,201325,201326,201327,201329,201330)
      group by 1
    ) sales
   on prod.ProductNo = sales.ProductNo
   left join -- do you really need an Outer Join?
    ( -- join Weeks and ServiceLevel 
      select
         serv.ProductNo,
         cast(sum(case when serv.WeekNo = 201330 then serv.Delivered end) as float) 
           / nullifzero(cast(sum(case when serv.WeekNo = 201330 then serv.Ordered end) as float)) as ServiceLevelThisWeek,
         cast(sum(case when serv.WeekNo = 201329 then serv.Delivered end) as float) 
           / nullifzero(cast(sum(case when serv.WeekNo = 201329 then serv.Ordered end) as float)) as ServiceLevelLastWeek,
         cast(sum(case when serv.WeekNo between 201324 and 201327 then serv.Delivered end) as float) 
           / nullifzero(cast(sum(case when serv.WeekNo between 201324 and 201327 then serv.Ordered end) as float)) as ServiceLevelAverage
      from ServiceLevel serv
      inner join Weeks week
              on serv.CalDate between week.WeekStartDate and week.WeekEndDate
      where weeks.WeekNo in (201324,201325,201326,201327,201329,201330)
      group by 1
    ) serv        
   on sales.ProductNo = serv.ProductNo
于 2013-09-26T16:15:31.257 回答