INSERT INTO … FROM SELECT … RETURNING id mappings

前端 未结 3 1660
梦谈多话
梦谈多话 2020-12-16 19:50

I\'m using PostgreSQL 9.3.

I want to duplicate some of the db records. Since I\'m using an auto-increment pk id for the table, I want to get back the id mappings fro

相关标签:
3条回答
  • 2020-12-16 19:57

    if id column of posts generated by nextval('posts_id_seq'::regclass) you can manually call this function for every new row

    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
    

    it'l works with any data, include non-unique title

    0 讨论(0)
  • 2020-12-16 20:14

    This would be simpler for UPDATE, where additional rows joined into the update are visible to the RETURNING clause:

    • Return pre-UPDATE Column Values Using SQL Only - PostgreSQL Version

    The same is currently not possible for INSERT. Per documentation:

    The expression can use any column names of the table named by table_name

    table_name being the target of the INSERT command.

    You can use (data-modifying) CTEs to get this to work.
    Assuming title to be unique per query, else you need to do more:

    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);
    

    If title is not unique per query (but at least id is unique per table):

    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);
    

    This second query relies on the undocumented implementation detail that rows are inserted in the order provided. It works in all current versions of Postgres and is probably not going to break.

    SQL Fiddle.

    0 讨论(0)
  • 2020-12-16 20:14

    The simplest solution IMHO would be to simply add a column to your table where you could put id of the row that was cloned.

    0 讨论(0)
提交回复
热议问题