1

我有一个订单表,其中每一行都有一个名为价格的列。这些订单中的每一个还有一个名为的列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 美元,正是那些使总金额大于 1000 美元的 300 美元。

我可以执行什么查询来找到它?

4

2 回答 2

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 美元的行进行罚款。

于 2013-07-18T15:20:57.147 回答
0

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

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 的版本快,因为根据窗口函数中已经使用的相同顺序选择第一个比为每一行计算一个值便宜得多,这不是sargable

我使用sum_price >= 1000,所以达到 1000 也完全符合条件。如果仅超出应限定使用>而不是>=.

窗口函数手册告知:

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

应该注意的是,与@Gordon 的查询相反,此查询始终只提供一行。在具有相同的多行created_at跨越 1000 障碍的情况下,它们都将符合 Gordon 的答案(或者它会失败,见下文),而只有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

阅读手册中的细则。

但无论哪种方式都比较慢。

-> SQL小提琴

于 2013-07-18T16:48:52.887 回答