PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

INSERT IN ... FROM SELECT ... RETURNING mappature id

Questo sarebbe più semplice per UPDATE , dove le righe aggiuntive unite nell'aggiornamento sono visibili a RETURNING clausola:

  • Restituisci i valori delle colonne pre-UPDATE utilizzando solo SQL - Versione PostgreSQL

Lo stesso è attualmente non possibile per INSERT . Per documentazione:

L'espressione può utilizzare qualsiasi nome di colonna della tabella denominata da nome_tabella

nome_tabella essendo l'obiettivo di INSERT comando.

Puoi utilizzare CTE (modifica dei dati) per farlo funzionare.
Supponendo title essere unici per query , altrimenti devi fare di più:

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

Se title non è univoco per query (ma almeno id è unico per tabella):

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

Questa seconda query si basa sui dettagli di implementazione non documentati che le righe vengono inserite nell'ordine fornito. Funziona in tutte le versioni attuali di Postgres e probabilmente non si romperà.

SQL Fiddle.