如何根据 Postgres 中的 INSERT RETURNING id 执行 SQL 更新?

Sov*_*iut 4 sql migration postgresql database-migration

我正在使用 Postgres。我有一张旧桌子和一张新桌子。旧表中的记录需要有新表中的相关记录。新表记录将有效地充当新表中记录的父项。

我正在尝试编写一个迁移,其中旧表中的每个“子”在新表中都有“父”。

OLD TABLE(我添加了一个外键,希望在迁移过程中填充它)

 id | name | new_id (FK)
----+------+-------------
  1 | 1st  | 
  2 | 2nd  |
Run Code Online (Sandbox Code Playgroud)

新表

 id | name 
----+------
    |
Run Code Online (Sandbox Code Playgroud)

我需要执行以下操作:

  • SELECT 旧表中的所有记录
  • INSERT 每个旧记录的新表中的记录和 RETURNING id
  • UPDATE 旧记录的外键值 RETURNING id

有没有办法使用集合查询来完成此操作?或者我是否需要开始深入研究 Postgres 特定的东西,比如LOOPs?

Mic*_*zzi 5

您可以使用可写的 cte,如下所示:

--open transaction
BEGIN;

--avoid concurrent writes
LOCK old_table IN ROW SHARE MODE;
LOCK new_table IN ROW SHARE MODE;

--create a sequence to populate new_table.id
CREATE SEQUENCE new_table_seq;

--using a writable cte to do the dirty job
WITH old_table_cte AS (
    UPDATE old_table SET new_id = nextval('new_table_seq') RETURNING *
)
INSERT INTO new_table SELECT new_id, name FROM old_table_cte;

--Create a proper FK
ALTER TABLE old_table ADD CONSTRAINT old_table_new_table_fk FOREIGN KEY (new_id) REFERENCES new_table (id);

--end transaction
COMMIT;
Run Code Online (Sandbox Code Playgroud)

这种方法有一些好处:

  • 按照您的要求利用 RETURNING,但在 update循序渐进。避免不必要的额外选择;
  • 并发安全;
  • 推迟 FK 创建将导致更快的脚本;
  • 采用纯SQL方案,无需使用过程语言;
  • 避免在同一步骤读取和写入 old_table。