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.