postgres CTE 中的多个更新语句

Posted

技术标签:

【中文标题】postgres CTE 中的多个更新语句【英文标题】:Multiple update statements in postgres CTE 【发布时间】:2019-08-08 11:19:20 【问题描述】:

我遇到了一个包含多个更新语句的 CTE 表达式的奇怪问题。

我可以使用以下 SQL 重现:-

DROP TABLE IF EXISTS foo;
DROP TABLE IF EXISTS baa;
CREATE TABLE foo(id BIGSERIAL, attributes JSONB);
CREATE TABLE baa(id BIGSERIAL, attributes JSON );
INSERT  INTO foo(attributes) SELECT jsonb_build_object('foo', 'baa');

WITH STEP_ONE AS (

    UPDATE foo 
    SET attributes = attributes ||jsonb_build_object('foo2', 'baa2')
    WHERE id = 1
    RETURNING attributes->>'foo' AS foo_att,id

), STEP_TWO AS (
    INSERT INTO baa(attributes)
    SELECT json_build_object('foo', id)
    FROM STEP_ONE
    RETURNING id as baa_id
) 
UPDATE foo
  SET attributes = attributes ||jsonb_build_object('baa', baa_id)
  FROM STEP_TWO
  WHERE id = 1

这不会更新表 foo。但是用“SELECT * FROM STEP_TWO”替换最终更新显示记录存在。

这是 postgresql 中的错误吗?还是我在文档中遗漏了有关在 CTE 中多次更新单个表的内容?

Postgres 版本:

PostgreSQL 11.4 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-9), 64-bit

【问题讨论】:

【参考方案1】:

是的,这个is documented:

所有语句都使用相同的快照执行(参见Chapter 13),因此它们无法“看到”彼此对目标表的影响。

您要么必须重写查询,以便每个表在语句中只修改一次,要么必须运行两个单独的语句。

【讨论】:

谢谢,我读过这篇文章,但将“子语句”误解为包含在 AS() 中的任何内容,显然最终语句也很重要

以上是关于postgres CTE 中的多个更新语句的主要内容,如果未能解决你的问题,请参考以下文章

Postgres 更新语句

递归 CTE 通过多个级别更新父记录

SQL 中with的用法

我更新到 MariaDB 10.2.20 以使用 CTE。在 phpMyAdmin 中仍然出现“无法识别的语句类型。(靠近 WITH)

如何在 postgres 中对相同的 CTE 表达式执行 UNION ALL?

Postgres - 使用 CTE 的 id 列的唯一值,与 GROUP BY 一起加入