【问题标题】:Postgres - updates with join gives wrong resultsPostgres - 使用连接更新会产生错误的结果
【发布时间】:2017-09-13 07:54:49
【问题描述】:

我很难理解我做错了什么。 此查询的结果对每一行显示相同的结果,而不是被正确的结果更新。

我的数据

我正在尝试更新一组业务的统计数据表

business_stats ( id SERIAL,
                 pk integer not null,
                 b_total integer,
                 PRIMARY KEY(pk)
                );

每个业务的详细信息都存储在这里

business_details (id SERIAL,
                  category CHARACTER VARYING,
                  feature_a CHARACTER VARYING,
                  feature_b CHARACTER VARYING,
                  feature_c CHARACTER VARYING
                  );

这里是一个将 pkcategory 相关联的表

datasets (id SERIAL,
          pk integer not null,
          category CHARACTER VARYING;
          PRIMARY KEY(pk)
          );

我做了什么(错误)

UPDATE business_stats
SET b_total = agg.total
FROM business_stats b,
     (  SELECT  d.pk, count(bd.id) total
        FROM business_details AS bd
            INNER JOIN datasets AS d
            ON bd.category = d.category
        GROUP BY d.pk
     ) agg
WHERE b.pk = agg.pk;

这个查询的结果是

 | id | pk |  b_total  |
 +----+----+-----------+
 |  1 | 14 |  273611   |
 |  2 | 15 |  273611   |
 |  3 | 16 |  273611   |
 |  4 | 17 |  273611   |

但如果我只运行 SELECT 则每个 pk 的结果完全不同

 | pk |  agg.total  |
 +----+-------------+
 | 14 |    273611   |
 | 15 |    407802   |
 | 16 |    179996   |
 | 17 |    815580   |

问题

  • 为什么会这样?
  • 为什么 WHERE 子句不起作用?

在写这个问题之前,我参考了这些帖子:abc

【问题讨论】:

  • business_detailsdatasets 是否具有相同的不同类别?
  • 添加一些外键,至少为了可读性。顺便说一句:为什么您的表同时具有(序列)id 和定义为主键的 int 字段?为什么business_details 没有主键?
  • 是的,在我的例子中,类别是 A、B、C 和 D,其中表 `datasets' pk 14 和 category 是 A , pk 15 和 category 是 B 等等。
  • WHERE 子句正在运行,但存在与 business_stats 的隐式自联接。尝试从 FROM 子句中删除 business_stats b, 并将 WHERE 更改为 business_stats.pk = agg.pk。但这没有经过测试,因为我懒得为测试表生成数据。
  • @wildpasser 我知道,当我开始从事这个项目时,我对如何处理表格一无所知。现在我正在尝试更新所有旧表,包括需要的 pk。

标签: postgresql join where


【解决方案1】:

执行以下操作(我始终建议不要在更新中加入)

UPDATE business_stats bs
SET b_total =
(  SELECT   count(c.id) total
        FROM business_details AS bd
        INNER JOIN datasets AS d
        ON bd.category = d.category
       where d.pk=bs.pk
 )
/*optional*/
where exists (SELECT  *
    FROM business_details AS bd
        INNER JOIN datasets AS d
        ON bd.category = d.category
   where d.pk=bs.pk)

【讨论】:

    【解决方案2】:

    问题在于您的 FROM 子句。对business_stats 的重复引用意味着您没有像预期的那样限制连接。您将加入 agg 反对第二次无关提及 business_stats 而不是您要更新的行。

    你所追求的是这样的(警告未测试):

    UPDATE business_stats AS b
    SET b_total = agg.total
    FROM
         (...) agg
    WHERE b.pk = agg.pk;
    

    【讨论】:

    • 确实,FROM 中重复出现的 busines_stats 使查询变得疯狂。我已经按照您展示的方式进行了重组,并且效果很好。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 2013-04-12
    • 2014-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多