在 CTE 中对一个日期范围内的列求和?

Summing a column over a date range in a CTE?

我正在尝试对特定日期范围内的特定列求和。更重要的是,我希望它成为一个 CTE,因为我必须多次使用它作为更大查询的一部分。由于它是 CTE,它必须有日期列以及总和和 ID 列,这意味着我必须按日期和 ID 进行分组。这将导致我的结果按 ID 和日期分组,给我的不是日期范围内的单个总和,而是一堆总和,每天一个。

为简单起见,假设我们有:

create table orders (  
 id int primary key,  
 itemID int foreign key references items.id,  
 datePlaced datetime,  
 salesRep int foreign key references salesReps.id,  
 price int,  
 amountShipped int);

现在,我们想要获得给定销售代表在一个会计年度中赚取的总金额,按项目细分。即忽略会计年度位:

select itemName, sum(price) as totalSales, sum(totalShipped) as totalShipped
 from orders
 join items on items.id = orders.itemID
 where orders.salesRep = '1234'
 group by itemName

很简单。但是当你添加任何其他东西时,甚至是价格,查询会吐出比你想要的更多的行。

    select itemName, price, sum(price) as totalSales, sum(totalShipped) as totalShipped
     from orders
 join items on items.id = orders.itemID
 where orders.salesRep = '1234'
 group by itemName, price

现在,每个组都是 (name, price) 而不仅仅是 (name)。这是一种 sudocode,但在我的数据库中,仅此更改就会导致我的结果集从 13 行跳到 32 行。再加上日期范围,你真的有问题了:

select itemName, price, sum(price) as totalSales, sum(totalShipped) as totalShipped  
 from orders  
 join items on items.id = orders.itemID  
 where orders.salesRep = '1234'  
  and orderDate between 150101 and 151231  
 group by itemName, price  

这与上一个示例相同。问题是让它成为 CTE:

with totals as (  
 select itemName, price, sum(price) as totalSales, sum(totalShipped) as totalShipped, orderDate as startDate, orderDate as endDate  
  from orders  
   join items on items.id = orders.itemID  
  where orders.salesRep = '1234'  
   and orderDate between startDate and endDate  
 group by itemName, price, startDate, endDate  
)  
select totals_2015.itemName as itemName_2015, totals_2015.price as price_2015, ...  
 totals_2016.itemName as itemName_2016, ...  
 from (  
 select * from totals  
 where startDate = 150101 and endDate = 151231  
) totals_2015  
 join (  
 select *  
 from totals  
 where startDate = 160101 and endDate = 160412  
) totals_2016  
on totals_2015.itemName = totals_2016.itemName  

现在,CTE 中的分组方式已经偏离了,而不是加上价格。我曾考虑过将价格查询分解为 CTE 中它自己的子查询,但我无法避免需要按日期分组以获得日期范围。任何人都可以解决这个问题吗?我希望我已经把事情说清楚了。这是针对 IBM iSeries 机器的 运行。谢谢!

根据您要查找的内容,这可能是更好的方法:

select 'by sales rep' breakdown
, salesRep
, '' year
, sum(price * amountShipped) amount
from etc
group by salesRep

union

select 'by sales rep and year' breakdown
, salesRep
, convert(char(4),orderDate, 120)  year
, sum(price * amountShipped) amount
from etc
group by salesRep, convert(char(4),orderDate, 120)

etc

如果可以按 id 列或外键分组,因为这些列已经编入索引,您将获得更快的结果。这适用于任何数据库。

with cte as (
select id,rep, sum(sales) sls, count(distinct itemid) did, count(*) cnt from sommewhere 
where date between x and y
group by id,rep
) select * from cte order by rep

或更花哨

with cte as (
select id,rep, sum(sales) sls, count(distinct itemid) did, count(*) cnt from sommewhere 
where date between x and y
group by id,rep
) select * from cte join reps on cte.rep = reps.rep order by sls desc

我最终找到了解决方案,它根本不需要 CTE。我希望 CTE 避免代码重复,但这几乎同样有效。 thread explaining summing conditionally 正是我想要的。