PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

INSERT INTO ... FROM SELECT ... RETURNING id mapeamentos


Isso seria mais simples para UPDATE , onde as linhas adicionais unidas à atualização ficam visíveis para o RETURNING cláusula:
  • Retornar valores de coluna pré-UPDATE usando apenas SQL - versão do PostgreSQL

O mesmo está atualmente não possível para INSERT . Por documentação:

A expressão pode usar qualquer nome de coluna da tabela nomeada por table_name

table_name sendo o alvo do INSERT comando.

Você pode usar CTEs (de modificação de dados) para fazer isso funcionar.
Assumindo title ser exclusivo por consulta , senão você precisa fazer mais:
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 não é único por consulta (mas pelo menos id é único por tabela):
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);

Essa segunda consulta depende do detalhe de implementação não documentado de que as linhas são inseridas na ordem fornecida. Funciona em todas as versões atuais do Postgres e provavelmente não vai quebrar.

SQL Fiddle.