(使用Postgres 9.1)
我的计划涉及杀虫剂喷雾器,试图根据原始目标喷洒多个实际单位。例如,喷雾器乔应该喷射10个目标,但他实际喷射了7个。
我提供的表格是所有计划目标(列= 目标)和实际目标(列= 实际)的摘要,以及其他一些数据,包括喷雾器的名称。这是架构:
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
+----+--------+--------+--------+---------+ | id | target | ref_id | actual | sprayer | +----+--------+--------+--------+---------+ | a | 1 | "l" | 10 | "Joe" | | a | 1 | "m" | 10 | "Joe" | | a | 1 | "p" | 10 | "Joe" | | c | 3 | "n" | 10 | "Joe" | | c | 3 | "o" | 10 | "Joe" | +----+--------+--------+--------+---------+
由于一对多连接和“c”重复两次,您可以看到 id 值“a”重复三次。鉴于此,我想要做的是显示目标值的SUM,“实际”值的SUM和喷雾器。我使用了以下查询:
SELECT SUM(target) targets, SUM(actual) actuals, sprayer FROM spray_summary GROUP BY sprayer
返回了结果:
+--------+--------+---------+ | target | actual | sprayer | +--------+--------+---------+ | 9 | 50 | "Joe" | +--------+--------+---------+
虽然实际值的总和是正确的(5 * 10 = 50),但目标值正在相乘,因为数据集是非规范化的。我希望“target”相对于 id 和 sprayer 是唯一的,所以我尝试了一个窗口函数:
SELECT SUM(target) OVER(PARTITION BY sprayer, id),
sprayer,
SUM(actual)
FROM spray_summary
GROUP BY sprayer, target, id
这给了我结果:
+--------+--------+---------+ | target | actual | sprayer | +--------+--------+---------+ | 1 | 30 | "Joe" | | 3 | 20 | "Joe" | +--------+--------+---------+
还是不对!正确的解决方案将提供以下内容:
+--------+--------+---------+ | target | actual | sprayer | +--------+--------+---------+ | 4 | 50 | "Joe" | +--------+--------+---------+
但无论我多少尝试调整窗口函数,行都会被拆分,因为我有到GROUP BY 目标,这会分散行。有任何想法吗?我知道这可以通过将表连接到自身来重写,一次用于SUM 目标,一次用于SUM 实际,但我没有这个选项。我只能修改列定义。
提前致谢。
编辑:我知道这可以通过将一些逻辑推入子查询来解决,但如果可能的话,我正在寻找列级解决方案。 SQL是自动生成的,所以我对结构没有多少控制权,但我可以修改列定义,因此我正在寻找列级解决方案,就像窗口函数一样。
最糟糕的情况是Postgres无法在列级别解决这个问题,我将不得不重新编写SQL生成器。
答案 0 :(得分:0)
select sum(target) as target, sum(actual) as actual, sprayer
from (
select
target,
sum(actual) as actual,
sprayer
from spray_summary
group by id, target, sprayer
) s
group by sprayer
order by sprayer
;
target | actual | sprayer
--------+--------+---------
4 | 50 | joe