PostgreSQL 中具有多个连接的 UPDATE 语句

Posted

技术标签:

【中文标题】PostgreSQL 中具有多个连接的 UPDATE 语句【英文标题】:UPDATE statement with multiple joins in PostgreSQL 【发布时间】:2015-11-29 21:57:42 【问题描述】:

我正在尝试更新一个名为 incode_warrants 的表,并将 warn_docket_noincode_violations 表中设置为 viol_docket_no

我在 Postgres 9.3 中有以下 SQL 查询,但是当它触发时出现以下错误:

Error : ERROR:  relation "iw" does not exist
LINE 1: update iw

我更像是一个 Active Record 人,所以我的原始 SQL 技能严重缺乏。我想知道是否有人可以帮助我指出正确的方向,了解如何正确进行此查询。

update iw
set iw.warn_docket_no = iv.viol_docket_no
from incode_warrants as iw
INNER JOIN incode_warrantvs as iwvs
on iw.warn_rid = iwvs.warnv_rid
INNER JOIN incode_violations as iv
ON iv.viol_citation_no = iwvs.warnv_citation_no and iv.viol_viol_no = iwvs.warnv_viol_no

【问题讨论】:

【参考方案1】:

这是我的代码,我在 a 和之后生成我的加入和附件,与我的可更新表和在我比较我的身份的地方,对不起我的英语

update cs_ticket ct
set site_name = a.name
from (
    select ct.id, cs."name" 
    from cs_ticket ct 
    inner join cs_net_segment cns 
    on ct.affected_ip like cns.ip || '.%'
    and end_date is null
    inner join cs_site cs 
    on cs.id = cns.site_id)a
where ct.id = a.id;

【讨论】:

【参考方案2】:
UPDATE incode_warrants iw
     SET warn_docket_no = iv.viol_docket_no
FROM incode_warrantvs AS iwvs, incode_violations AS iv 
WHERE iv.viol_citation_no = iwvs.warnv_citation_no AND
      iv.viol_viol_no = iwvs.warnv_viol_no AND
      iw.warn_rid = iwvs.warnv_rid;

【讨论】:

【参考方案3】:

与 Postgres 中的有效 UPDATE 语句相同:

UPDATE incode_warrants iw
SET    warn_docket_no = iv.viol_docket_no
FROM   incode_warrantvs  iwvs
JOIN   incode_violations iv ON iv.viol_citation_no = iwvs.warnv_citation_no
                           AND iv.viol_viol_no = iwvs.warnv_viol_no
WHERE  iw.warn_rid = iwvs.warnv_rid;
-- AND iw.warn_docket_no IS DISTINCT FROM iv.viol_docket_no -- see below

您不能只使用FROM 子句中的表别名作为UPDATE 子句中的目标表。要更新的(一个!)表紧跟在 UPDATE 关键字之后(如果我们忽略两者之间可能的 ONLY 关键字)。如果需要,您可以在此处添加别名。这是您的错误消息的直接原因,但还有更多。

要更新的列总是来自一个要更新的表,不能是表限定的。

您不需要在FROM 子句中重复目标表 - 像这样的特殊情况除外:

PostgreSQL: update with left outer self join ignored

此可选添加可以通过抑制不改变任何内容的更新来避免无意义的成本:

AND iw.warn_docket_no IS DISTINCT FROM iv.viol_docket_no

见:

How do I (or can I) SELECT DISTINCT on multiple columns?

More in the excellent manual on UPDATE.

【讨论】:

很好的答案,感谢您的帮助和专业知识。我一定会阅读手册并提高我的技术! 如果您不介意,我确实有一个问题。我试图让这个更新语句在 MASSIVE 400 LOC 存储过程中触发。我已经将它注入到 SP 中,并设置了一个 Raise 信息来记录它何时触发,但在运行存储过程时它永远不会触发。自行运行更新工作正常。我应该创建一个新问题来解决这个问题吗? @shakycode:是的,一个包含所有必要细节的新问题是正确的举措。评论不是地方。您可以随时链接到这个以获取上下文。 会的!我需要以某种方式匿名存储过程,因为它具有专有的模式数据。我很快就会发布。再次感谢您的帮助,欧文!【参考方案4】:

你更新一个表,而不是加入

update incode_warrants ALIAS
set warn_docket_no = iv.viol_docket_no
from incode_warrantvs as iw 
...

【讨论】:

您不能在 Postgres 中对 UPDATE 语句的目标列进行表限定。 @ErwinBrandstetter 感谢您的评论。我修复它。但我的回答只是解决了一个问题,在看到你的回答后意识到这不是一个完整的答案。【参考方案5】:

您的查询应如下所示:

UPDATE incode_warrants
SET warn_docket_no = incode_violations.viol_docket_no
FROM incode_violations
WHERE incode_violations.viol_citation_no = incode_warrants.warnv_citation_no
AND incode_violations.viol_viol_no = incode_warrants.warnv_viol_no;

您不需要任何其他加入。使用此查询,您只需使用另一个表中的列中的值更新一个表中的列。当然,只有在WHERE 条件为真时才会更新。

【讨论】:

感谢您的快速回答。当我运行它时,我得到了这个:Error : ERROR: column incode_warrants.warnv_citation_no does not exist LINE 4: WHERE incode_violations.viol_citation_no = incode_warrants.w... 你能用模式更新你的问题吗?我不敲你的桌子是什么样子的。需要更多解释。 您可能忽略了 incode_warrantsincode_warrantvs 是两个不同的表 - 当然,除非这是问题中的拼写错误。 正如 Erwin 提到的,这个解决方案缺少 incode_warrantvs 这就是我投反对票的原因。

以上是关于PostgreSQL 中具有多个连接的 UPDATE 语句的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 PostgreSQL 中的变量创建具有内部连接的视图?

PostgreSQL 中具有特定模式的 Linq 和实体迁移

PostgreSQL:多个存在返回不正确的结果

具有两个内部连接的 PostgreSQL 查询

如何根据PostgreSQL中同一行的两个不同列更新具有唯一序列号的列?

PostgreSQL 中多个表的完全外连接