CREATE TABLE inventory_box (
box_id varchar(10),
value integer
);
INSERT INTO inventory_box VALUES ('1', 10), ('2', 15), ('3', 20);
我准备了一个sql fiddle与模式。
我想选择合计值(value)在20以上的库存箱列表
possible result 1. box 1 + box 2 (10 + 15 >= 20)
这是我现在正在做的事情:
SELECT * FROM inventory_box LIMIT 1 OFFSET 0;
-- count on the client side and see if I got enough
-- got 10
SELECT * FROM inventory_box LIMIT 1 OFFSET 1;
-- count on the client side and see if I got enough
-- got 15, add it to the first query which returned 10
-- total is 25, ok, got enough, return answer
我正在寻找一种一旦达到目标值就会停止扫描的解决方案
最佳答案
一种可能的方法是按 box_id 顺序扫描表,直到总数超过 30,然后返回所有前面的行加上使总和超过限制的行。请注意,当达到总和时扫描不会停止,它会对整个表进行总计,然后返回结果以选择结果。
http://sqlfiddle.com/#!15/1c502/4
SELECT
array_agg(box_id ORDER BY box_id) AS box_ids,
max(boxsum) AS boxsum
FROM
(
SELECT
box_id,
sum(value) OVER (ORDER BY box_id) AS boxsum,
sum(value) OVER (ORDER BY box_id ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS prevboxsum
FROM
inventory_box
) x
WHERE prevboxsum < 30 OR prevboxsum IS NULL;
但实际上,在 SQL 中以通用且可靠的方式(或根本不这样做)会非常可怕。
如果愿意,您可以ORDER BY value ASC
而不是ORDER BY box_id
;这将从最小到最大添加框。但是,如果您随后从池中移除所有小方 block 并再次运行并重复,这将发生灾难性的失败。很快它就会低效地将两个大盒子混在一起。
要解决一般情况下的这个问题,找到最小组合是一个困难的优化问题,可能受益于不精确的基于样本和概率的方法。
要按顺序扫描表直到总和达到目标,锁定表然后使用 PL/PgSQL 从游标中读取行,该游标以 value
顺序返回行加上一个 array_agg (box_id) OVER(按值排序)
和 sum(value) OVER(按值排序)
。当您达到所需的总和时,返回当前行的数组。这不会产生一个最佳解决方案,但它会产生一个一个解决方案,而且我认为如果在地方。
关于sql - Postgres : limit by the results of a sum function,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22623148/