删除/插入行的 SQL CTE 语法

vol*_*ron 5 sql postgresql common-table-expression postgresql-9.2

从表中删除,然后插入到同一个表并返回插入值的 CTE 语法是什么?

运行 2 小时的睡眠,有些事情看起来不对劲(除了这不会执行的事实):

WITH delete_rows AS (
   DELETE FROM <some_table> WHERE id = <id_value>
   RETURNING *
)
SELECT * FROM delete_rows
UNION
(
   INSERT INTO <some_table> ( id, text_field )
      VALUES ( <id_value>, '<text_field_value>' )
      RETURNING *
)
Run Code Online (Sandbox Code Playgroud)

预期的行为是首先清除一个 ID 的所有记录,然后插入相同 ID 的记录(故意不是 upsert)并返回那些插入的记录(不是删除)。

Erw*_*ter 6

您的问题更新明确表明您不能在一个声明中做到这一点。

打包到同一语句的 CTE 中,两个操作(INSERTDELETE)将看到表的相同快照并几乎同时执行。即,INSERT仍然会看到您认为已经删除的所有行。根据文档:

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

您可以将它们作为两个独立的语句包装到同一个事务中——这似乎也不是绝对必要的,但它会允许整个操作以原子方式成功/失败:

BEGIN;

DELETE FROM <some_table> WHERE id = <id_value>;

INSERT INTO <some_table> (id, text_field)
VALUES ( <id_value>, '<text_field_value>')
RETURNING *;

COMMIT;
Run Code Online (Sandbox Code Playgroud)

现在,INSERT可以看到DELETE.