Postgres 中的子查询根据 sum 函数给出不正确的结果
Posted
技术标签:
【中文标题】Postgres 中的子查询根据 sum 函数给出不正确的结果【英文标题】:Subquery in Postgres giving incorrect result based on sum function 【发布时间】:2018-05-29 20:57:06 【问题描述】:WITH eas AS
(
SELECT
DATE_TRUNC('week',create_ts)::DATE - '1 day'::INTERVAL AS DATE
,COUNT(name) AS ase
FROM local
WHERE type='sr'
GROUP BY DATE_TRUNC('week',create_ts)::DATE - '1 day'::INTERVAL
)
, ias AS
(
SELECT
DATE_TRUNC('week',create_ts)::DATE - '1 day'::INTERVAL AS DATE
,COUNT(name) AS ase
FROM local
WHERE type='sr'
AND state NOT IN ('AZ','CA')
GROUP BY DATE_TRUNC('week',create_ts)::DATE - '1 day'::INTERVAL
)
SELECT
DATE_TRUNC('week',eas.date)::DATE - '1 day'::INTERVAL AS l_create
,ase + asi AS count
FROM eas FULL JOIN ias
ON ias.date = eas.date
GROUP BY ase
,asi
,DATE_TRUNC('week',eas.date)::DATE - '1 day'::INTERVAL
ORDER BY DATE_TRUNC('week',eas.date)::DATE - '1 day'::INTERVAL ASC
如果我运行第一条语句,它会给出以下结果:
3/18/18 0:00 21
3/25/18 0:00 46
4/1/18 0:00 25
4/8/18 0:00 25
第二句话:
3/18/18 0:00 67
3/25/18 0:00 129
4/1/18 0:00 148
4/8/18 0:00 138
如果我运行完整的查询:
2018-03-18 00:00:00 175
2018-03-25 00:00:00 173
2018-04-01 00:00:00 163
而想要的结果是:
3/18/18 0:00 88
3/25/18 0:00 175
4/1/18 0:00 173
4/8/18 0:00 163
我错过了什么??
【问题讨论】:
好吧,首先你缺少循环。您的代码中没有循环。你正在做的是 CTE 中的 SELECT “我错过了什么??”发布表的结构(如CREATE TABLE
)并解释循环的含义。这是 PL/pgSQL 循环的一部分吗?请出示。
但是对于这个简单的查询,CTE 还不够吗?对不起这里的新手
@stickybit,循环是指代码的“eas”和“aes”部分
我只是说这些不是循环。它们是公用表表达式中的选择语句。
【参考方案1】:
错误在最后一条语句中。您出于某种原因按每一列分组并在此处执行加法:ase + asi
。相反,我会尝试替换以下行:
,ase + asi AS count
...
GROUP BY ase, asi, DATE_TRUNC('week',eas.date)::DATE - '1 day'::INTERVAL
与
,sum(ase)+sum(asi) AS count
...
GROUP BY DATE_TRUNC('week',eas.date)::DATE - '1 day'::INTERVAL
实际上使用聚合函数将每个日期的 ase
和 asi
的计数相加,因此查询的最后部分如下所示
SELECT
DATE_TRUNC('week',eas.date)::DATE - '1 day'::INTERVAL AS l_create
,sum(ase)+sum(asi) AS count
FROM eas FULL JOIN ias
ON ias.date = eas.date
GROUP BY DATE_TRUNC('week',eas.date)::DATE - '1 day'::INTERVAL
ORDER BY DATE_TRUNC('week',eas.date)::DATE - '1 day'::INTERVAL ASC
要进一步调查为什么会发生这种情况,您需要删除 GROUP BY
子句并查看数据以亲自了解 FULL JOIN
的作用。
示例
下面我附上了一个重现您的问题的示例历史记录,但我使用整数而不是日期列(对于您的情况没有区别)。
postgres=# create table a(dt int, cnt int);
CREATE TABLE
postgres=# create table b(dt int, cnt int);
CREATE TABLE
postgres=# insert into a values (1,21),(2,46),(3,25),(4,25);
INSERT 0 4
postgres=# insert into b values (1,67),(2,129),(3,148),(4,138);
INSERT 0 4
postgres=# select a.dt,sum(a.cnt)+sum(b.cnt) from a full join b on a.dt=b.dt group by a.dt order by a.dt;
dt | ?column?
----+----------
1 | 88
2 | 175
3 | 173
4 | 163
【讨论】:
它对我有用,我刚刚在我的样本上测试过。附上代码。【参考方案2】:WITH eas AS
(
SELECT
DATE_TRUNC('week',create_ts) AS DATE
,COUNT(name) AS ase
FROM local
WHERE type='sr'
GROUP BY DATE_TRUNC('week',create_ts)
)
, ias AS
(
SELECT
DATE_TRUNC('week',create_ts) AS DATE
,COUNT(name) AS ase
FROM local
WHERE type='sr'
AND state NOT IN ('AZ','CA')
GROUP BY DATE_TRUNC('week',create_ts)
)
SELECT
DATE_TRUNC('week',eas.date)::DATE - '1 day'::INTERVAL AS l_create
,ase + asi AS count
FROM eas FULL JOIN ias
ON ias.date = eas.date
GROUP BY ase
,asi
,DATE_TRUNC('week',eas.date)::DATE - '1 day'::INTERVAL
ORDER BY DATE_TRUNC('week',eas.date)::DATE - '1 day'::INTERVAL ASC
这解决了它!谢谢大家!
【讨论】:
以上是关于Postgres 中的子查询根据 sum 函数给出不正确的结果的主要内容,如果未能解决你的问题,请参考以下文章
具有 SUM 聚合的 Postgres CASE 条件评估不需要的 ELSE 部分
SQL 编译错误:无法评估不受支持的子查询类型 - SELECT 子句中的函数调用