我正在制作一份报告,以显示产品级别的销售情况,并且需要包含销售每种产品的商店数量。我的销售数据按周分类,但我还需要包含每日级别的服务级别统计信息。
我遇到的问题是,当我尝试计算每个产品的销售数量时,它会乘以最多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字段中这样做
答案 0 :(得分:2)
首先,我认为您当前的方法也不会为其他列计算正确的值。例如。每个ServiceLevel行将对每个SalesValue求和一次:
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