【发布时间】:2018-04-28 07:19:44
【问题描述】:
我正在使用 Postresql 9.6,并试图弄清楚如何创建一个查询来根据不同列的离散总和(都在同一个表中)计算列的总和。例如,我希望每组行的计数总和直到体积 >= 100,然后重新开始计算计数总和。
示例数据:
id count volume
1 5 12
2 6 14
3 2 11
4 10 9
5 5 14
6 17 19
7 0 8
8 12 4
9 18 6
10 12 14
11 10 10
12 15 7
13 8 12
14 2 17
15 5 30
16 9 24
17 2 16.5
假设的中间结果(只是为了理解我的期望):
id sum(count) discrete volume
1 5 12
2 11 26
3 13 37
4 23 46
5 28 60
6 45 79
7 45 87
8 57 91
9 75 97
10 87 111
11 10 10 (reset since volume >= 100)
12 25 17
13 33 29
14 35 46
15 40 76
16 49 100
17 2 16.5 (reset since volume >= 100)
预期的最终结果:
sum(count) discrete volume
87 111
49 100
2 16.5 (partial result, which is desired)
到目前为止我尝试过的:SQL Fiddle
我从another StackOverflow answer 获得了SQL Fiddle 中显示的当前查询的想法,这显然不能正常工作(但是对于我试图解决的另一个问题,它工作得很好)。我从different StackOverflow answer 看到我可能想使用 RECURSIVE 查询(PostgreSQL Documentation),但我不知道如何正确编写查询以便它工作:(
我当然可以用 Java 代码编写它(并且已经有了),但我想用 SQL 编写它,因此希望它比读取所有行并计算结果更快。我也很可能编写一个存储过程来完成这项工作,但我宁愿避免这种情况,因为我正在使用 JPA(在本例中使用本机查询)并希望将所有代码保存在同一个位置( Java 代码库)。另外,我希望能够动态包含/排除列,所以我想在 Java 代码中构造查询(实际表的列比我的示例多得多)。
感谢您提供的任何帮助。
编辑:
感谢@klin 的评论并查看引用的 StackOverflow 问题,我越来越接近了。这是我所拥有的(生成中间结果):
WITH RECURSIVE WorkTable(id, count_sum, volume_sum) AS
(
SELECT
id,
count AS count_sum,
volume AS volume_sum
FROM measurements
WHERE id = 1
UNION ALL
SELECT
measurements.id,
CASE WHEN WorkTable.volume_sum >= 100
THEN measurements.count
ELSE WorkTable.count_sum + measurements.count
END AS count_sum,
CASE
WHEN WorkTable.volume_sum >= 100
THEN measurements.volume
ELSE WorkTable.volume_sum + measurements.volume
END AS discrete_sum_volume
FROM measurements
JOIN WorkTable
ON measurements.id = WorkTable.id + 1
)
SELECT *
FROM WorkTable
ORDER BY id
但是,我仍然缺少的是如何获得最终结果。如果我使用 WHERE volume_sum >= 100 我不会得到最终(部分)结果。而且我不能使用OR id = MAX(id),因为 Postgres 不允许在 WHERE 子句中使用它。
编辑:顺便说一句,@klin 和 @JorgeCampos 花费了所有的工作和时间来查看和回答我的问题,我发现此查询不适用于具有数百万行的表。我创建了一个存储过程;我不想去那里,但似乎没有其他表现良好的选择。对于大型表,存储过程的性能比 RECURSIVE 查询要好几个数量级。
【问题讨论】:
-
你的意思是
until volume <= 100对吧? -
@JorgeCampos - 我尝试根据您的问题编辑问题,但它似乎读起来不太清楚。重置条件为
volume >= 100 -
有两种解决类似问题的方法——迭代和递归。这两个例子都可以在这个线程中找到Find Value per number based on Above row result.
-
@klin 感谢您的回复。迭代方法似乎需要一个我试图避免的存储过程(原因见问题文本)。如果可能的话,我想要一个递归解决方案(我不确定)。我一直在研究递归查询几乎整整一天,但到目前为止我没有任何尝试。
-
对于您当前的尝试,解决方案是根据该 case 语句创建一个行号并仅获取 number=1 的行,但是您假设您的查询没有间隙ids 和我特别不同意。该表上的任何删除或手动插入都会完全破坏您的功能。
标签: postgresql