计算teradata结果集中的不同项目

时间:2013-09-26 13:35:28

标签: sql teradata

我正在制作一份报告,以显示产品级别的销售情况,并且需要包含销售每种产品的商店数量。我的销售数据按周分类,但我还需要包含每日级别的服务级别统计信息。

我遇到的问题是,当我尝试计算每个产品的销售数量时,它会乘以最多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字段中这样做

1 个答案:

答案 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