INSERT INTO ... FROM SELECT ... RETURNING id mappings

fen*_*e87 9 sql postgresql sql-insert sql-returning

我正在使用PostgreSQL 9.3.

我想复制一些db记录.由于我正在为表使用自动增量pk id,因此我想从生成的重复记录ID返回到原始ID的id映射.例如,假设我有一个posts包含2条记录的表:

 [{'id': 1, 'title': 'first'}
, {'id': 2. 'title': 'second'}]
Run Code Online (Sandbox Code Playgroud)

使用SQL:

INSERT INTO posts (title) SELECT title FROM posts RETURNING id, ??
Run Code Online (Sandbox Code Playgroud)

我希望看到像这样的映射:

 [{'id': 3, 'from_id': 1}
, {'id': 4, 'from_id': 2}]
Run Code Online (Sandbox Code Playgroud)

有关如何填写上述问号以使其有效的任何想法?非常感谢!

Erw*_*ter 9

这对于子句UPDATE是可见的更加简单,其中加入更新的其他行是可见的RETURNING:

目前不可能这样做INSERT.每个文件:

表达式可以使用table_name指定的表的任何列名

table_nameINSERT命令的目标.

您可以使用(数据修改)CTE来实现此功能.
假设每个查询title都是唯一的,否则你需要做更多:

WITH sel AS (
   SELECT id, title
   FROM   posts
   WHERE  id IN (1,2)   -- select rows to copy
   )
,    ins AS (
   INSERT INTO posts (title)
   SELECT title FROM sel
   RETURNING id, title
 )
SELECT ins.id, sel.id AS from_id
FROM   ins
JOIN   sel USING (title);
Run Code Online (Sandbox Code Playgroud)

如果title每个查询不唯一(但id每个表至少是唯一的):

WITH sel AS (
   SELECT id, title, row_number() OVER (ORDER BY id) AS rn
   FROM   posts
   WHERE  id IN (1,2)   -- select rows to copy
   ORDER  BY id
   )
,    ins AS (
   INSERT INTO posts (title)
   SELECT title FROM sel ORDER  BY id  -- ORDER redundant to be sure
   RETURNING id
 )
SELECT i.id, s.id AS from_id
FROM  (SELECT id, row_number() OVER (ORDER BY id) AS rn FROM ins) i
JOIN   sel s USING (rn);
Run Code Online (Sandbox Code Playgroud)

第二个查询依赖于未提供的实现细节,即按所提供的顺序插入行.它适用于所有当前版本的Postgres,可能不会破坏.

SQL小提琴.

  • 关于“*查询依赖于未记录的实现细节,即按提供的顺序插入行*”,@AdrianKlaver [指出我](/sf/ask/5356310571/ and-get-the-old-new-matching-information#comment134916842_76518722) 到 https://www.postgresql.org/message-id/1678721.1681566044%40sss.pgh.pa.us 汤姆·莱恩 (Tom Lane) 写道“*我们 [...]拒绝了 INSERT 必须保留传入元组顺序的想法。*” (2认同)

Mat*_*riy 6

如果idpostsserial类型,它的产生一样nextval('posts_id_seq'::regclass),你可以手动调用这个函数为每一个新行

with
sel as (
  SELECT id, title, nextval('posts_id_seq'::regclass) new_id
  FROM   posts
  WHERE  id IN (1,2)
),
ins as (
  INSERT INTO posts (id, title)
  SELECT new_id, title
  FROM sel
)
SELECT id, new_id
FROM sel
Run Code Online (Sandbox Code Playgroud)

它适用于任何数据,包括非唯一的 title