2013-07-18 145 views
1

我有一个订单表,其中的每一行都有一个名为price的列。每个订单还有一个名为created_at的专栏,该专栏将说明订单何时创建。获取订单号,使订单总数为1000

什么是一个很好的方法来找出哪些订单使总价格超过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

主键是一个名为uuid的列,它是一个唯一的字符串。 –

回答

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's version更快,因为采摘根据第一相同的已经在窗口函数中使用的顺序比计算每行的值要便宜很多,这不是sargable

我使用sum_price >= 1000,所以达到1000也完全符合要求。如果只有超过应符合使用>而不是>=

The manual on window functions informs:

除了这些功能,任何内建或用户定义的聚合 函数可以被用作一个窗函数

应当注意,这个查询总是只提供一行,而不是@戈登的查询。如果有多行created_at跨越1000个障碍,所有这些行将符合Gordon的答案(否则将失败,请参阅下文),而在我的领域中只有one。这将是一个任意的,只要你不添加更多的项目ORDER BY作为tiebreaker。像:

ORDER BY created_at, order_id 

有ORDER的两个实例通过这个查询,它只是碰巧,你可以修改的一个或两个,使其工作。为了使排序顺序一致,这应该是最快的。

其实,戈登的版本将完全失败本次测试的情况:

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

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的行。

+0

嗨戈登,什么是o2?我猜是从订单o2的内部。 –

+0

@HommerSmith:'o2'只是一个错字。你可以在这里删除*所有*表资格和表别名。但是,对于重复的'created_at',此查询可能会完全失败。我在我的回答中添加了一段。 –