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

实际上使用聚合函数将每个日期的 aseasi 的计数相加,因此查询的最后部分如下所示

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 函数给出不正确的结果的主要内容,如果未能解决你的问题,请参考以下文章

Postgres:计算子查询中的唯一数组条目

具有 SUM 聚合的 Postgres CASE 条件评估不需要的 ELSE 部分

SQL 编译错误:无法评估不受支持的子查询类型 - SELECT 子句中的函数调用

如何在 jpa 查询中调用 postgres position() 函数

该语句中的子查询在哪里?

查询分组中的 Oracle SQL 条件聚合函数