【发布时间】:2014-03-13 00:13:30
【问题描述】:
(使用 Postgres 9.1)
我的程序处理杀虫剂喷雾器试图根据原始目标喷洒多个实际单位。例如,喷雾器 Joe 应该喷洒 10 个目标,但他实际上喷洒了 7 个。
我得到了一个表格,其中汇总了所有计划目标(column= targets)和实际目标(column= actual),以及其他一些数据,包括喷雾器的名字。这是架构:
CREATE TABLE spray_summary
(
id character varying(1),
target integer,
ref_id character varying(1),
actual integer,
sprayer character varying(25)
)
数据是 (id, target) 和 (ref_id, actual, sprayer) 之间的非规范化连接,但现在我只需要处理这个表。以下是完整结果:
SELECT * FROM spray_summary
+----+--------+--------+--------+---------+
|编号 |目标 | ref_id |实际 |喷雾器|
+----+--------+--------+--------+---------+
|一个 | 1 | "l" | 10 | “乔” |
|一个 | 1 | “米” | 10 | “乔” |
|一个 | 1 | "p" | 10 | “乔” |
| c | 3 | "n" | 10 | “乔” |
| c | 3 | "o" | 10 | “乔” |
+----+--------+--------+--------+---------+
您可以看到 id 值“a”由于一对多连接重复了 3 次,而“c”重复了 2 次。鉴于此,我想做的是显示 target 值的 SUM、“实际”值的 SUM 和喷雾器。我使用了以下查询:
SELECT SUM(target) targets, SUM(actual) actuals, sprayer FROM spray_summary GROUP BY sprayer
返回结果:
+--------+--------+---------+ |目标 |实际 |喷雾器| +--------+--------+---------+ | 9 | 50 | “乔” | +--------+--------+---------+虽然 实际 值的总和是正确的 (5 * 10 = 50),但由于数据集非规范化,目标 值正在相乘。我希望“目标”相对于 id 和 sprayer 是唯一的,所以我尝试了一个窗口函数:
SELECT SUM(target) OVER(PARTITION BY sprayer, id),
sprayer,
SUM(actual)
FROM spray_summary
GROUP BY sprayer, target, id
这给了我结果:
+--------+--------+---------+ |目标 |实际 |喷雾器| +--------+--------+---------+ | 1 | 30 | “乔” | | 3 | 20 | “乔” | +--------+--------+---------+还是不对!正确的解决方案将提供以下内容:
+--------+--------+---------+ |目标 |实际 |喷雾器| +--------+--------+---------+ | 4 | 50 | “乔” | +--------+--------+---------+但无论我如何尝试调整窗口函数,行都会被拆分,因为我 有 到 GROUP BY target 这会分解行。有任何想法吗?我知道这可以通过将表与自身连接来重写,一次用于 SUM target,一次用于 SUM actual,但我没有该选项。我只能修改列定义。
提前致谢。
编辑:我知道这可以通过将一些逻辑推入子查询来解决,但如果可能的话,我正在寻找列级解决方案。 SQL 是自动生成的,因此我对结构没有太多控制,但我可以修改列定义,因此我正在寻找列级解决方案,例如窗口函数。
最坏的情况是 Postgres 无法在列级别解决这个问题,我将不得不重新编写 SQL 生成器。
【问题讨论】:
-
加入前不能聚合目标?
-
您可以尝试从 select 中进行选择,但这不是分析查询的好用例
-
一种解决方案是提前聚合,但是这段代码是通过Java自动生成的,我对整个结构没有太多控制权,只有列值。这是一个不幸的限制。
标签: sql postgresql aggregate-functions