获取使订单总数为1000的订单号

时间:2013-07-18 15:12:40

标签: sql postgresql sum window-functions running-total

我有一个Orders表,其中每一行都有一个名为price的列。这些订单中的每一个都有一个名为created_at的列,该列将说明何时创建该订单。

找出哪个订单使价格总额超过1000美元会有什么好方法?

所以,想象一下,我有三个看起来像这样的命令:

Order 1: price: $800 - created_at: 2013/07/11 

Order 2: price: $100 - created_at: 2013/07/13 

Order 3: price: $300 - created_at: 2013/07/14 

我有兴趣发现订单3是让我超过1000美元的订单,因为如果我们加上800美元+ 100美元+ 300美元,那么正好是300美元,这使得总金额超过1000美元。

我可以执行哪些查询来查找?

2 个答案:

答案 0 :(得分:0)

为此,你需要一个累积和,Postgres提供了一个窗函数:

select o.*
from (select o.*,
             sum(o2.price) over (order by created_at) as cumsum
      from orders o
     ) o
where 1000 > cumsum - price and 1000 <= cumsum;

where子句只是罚款加上价格首先超过$ 1000的行。

答案 1 :(得分:0)

使用窗口聚合函数sum()计算运行总和后,只需选择超过1000的created_at的第一行:

SELECT *
FROM (
   SELECT order_id, created_at
        , sum(price) OVER (ORDER BY created_at) AS sum_price
   FROM   orders
   ) sub
WHERE  sum_price >= 1000
ORDER  BY created_at 
LIMIT  1;

这应该比@Gordon's version更快,因为根据窗口函数中已经使用的相同顺序选择第一个比计算每行的值要便宜得多,这不是sargable

我使用sum_price >= 1000,因此达到1000也完全合格。如果只有超过才有资格使用>代替>=

The manual on window functions informs:

  

除了这些功能外,还有任何内置或用户定义的聚合   函数可以用作窗口函数

应该注意的是,这个查询总是只提供一行,而不是@Gordon的查询。如果多行具有相同的created_at跨越1000障碍,则所有这些行都符合戈登的答案(或者它会失败,见下文),而我的选择只有one。这将是一个任意的,只要您不添加更多项目作为决胜局ORDER BY。像:

ORDER BY created_at, order_id

此查询中有两个ORDER BY实例,您可以修改其中一个或两个以使其正常工作。为了使排序顺序相同,这样做应该是最快的。

实际上,对于这个测试用例,Gordon的版本完全失败:

CREATE TEMP TABLE orders(order_id int, price int, created_at date);

INSERT INTO orders VALUES
  (1, 500, '2013-07-01')
 ,(2, 400, '2013-07-02')
 ,(3, 100, '2013-07-03')
 ,(4, 100, '2013-07-03')
 ,(5, 100, '2013-07-03');

您可以通过使窗口函数中的排序顺序与上面所示的一样独特来修复它。

您可以将窗口函数的框架定义更改为:

ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

Read the fine print in the manual.

但无论如何它都会变慢。

-> SQLfiddle