我有一个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美元。
我可以执行哪些查询来查找?
答案 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.
但无论如何它都会变慢。