Versão final
... depois de mais algumas informações do OP. Considere esta demonstração:
-- DROP TABLE foo; DROP TABLE bar;
CREATE TEMP TABLE bar (
id serial PRIMARY KEY -- using a serial column!
,z integer NOT NULL
);
CREATE TEMP TABLE foo (
id serial PRIMARY KEY -- using a serial column!
,x integer NOT NULL
,y integer NOT NULL
,bar_id integer UNIQUE NOT NULL REFERENCES bar(id)
);
Inserir valores -
bar
primeiro.Seria muito útil se você forneceu dados de teste em sua pergunta assim!
INSERT INTO bar (id,z) VALUES
(100, 7)
,(101,16)
,(102,21);
INSERT INTO foo (id, x, y, bar_id) VALUES
(1, 3,4,100)
,(2, 9,6,101)
,(3,18,0,102);
Defina as sequências para os valores atuais ou obtemos violações de chave duplicadas:
SELECT setval('foo_id_seq', 3);
SELECT setval('bar_id_seq', 102);
Verificações:
-- SELECT nextval('foo_id_seq')
-- SELECT nextval('bar_id_seq')
-- SELECT * from bar;
-- SELECT * from foo;
Inquerir:
WITH a AS (
SELECT f.x, f.y, bar_id, b.z
FROM foo f
JOIN bar b ON b.id = f.bar_id
WHERE x > 3
),b AS (
INSERT INTO bar (z)
SELECT z
FROM a
RETURNING z, id AS bar_id
)
INSERT INTO foo (x, y, bar_id)
SELECT a.x, a.y, b.bar_id
FROM a
JOIN b USING (z);
Isso deve fazer o que sua última atualização descreve.
A consulta assume que
z
é UNIQUE
. Se z
não é único, fica mais complexo. Consulte a Consulta 2 nesta resposta relacionada para uma solução pronta usando a função de janela row_number()
nesse caso. Além disso, considere substituir a relação 1:1 entre
foo
e bar
com uma única mesa unida. CTE de modificação de dados
Segunda resposta após mais informações.
Se você deseja adicionar linhas a
foo
e bar
em uma única consulta, você pode usar um CTE de modificação de dados desde o PostgreSQL 9.1 :WITH x AS (
INSERT INTO bar (col1, col2)
SELECT f.col1, f.col2
FROM foo f
WHERE f.id BETWEEN 12 AND 23 -- some filter
RETURNING col1, col2, bar_id -- assuming bar_id is a serial column
)
INSERT INTO foo (col1, col2, bar_id)
SELECT col1, col2, bar_id
FROM x;
Eu desenho valores de
foo
, insira-os em bar
, devolva-os junto com um bar_id
gerado automaticamente e insira isso em foo
. Você também pode usar outros dados. Aqui está uma demonstração de trabalho para brincar no sqlfiddle.
Noções básicas
Resposta original com informações básicas antes dos esclarecimentos.
A forma básica é:
INSERT INTO foo (...)
SELECT ... FROM foo WHERE ...
Não é necessário parênteses. Você pode fazer o mesmo com qualquer tabela
INSERT INTO foo (...)
SELECT ... FROM bar WHERE ...
E você pode juntar-se à tabela que você insere no SELECT:
INSERT INTO foo (...)
SELECT f.col1, f.col2, .. , b.bar_id
FROM foo f
JOIN bar b USING (foo_id); -- present in foo and bar
É apenas um SELECT como qualquer outro - que pode incluir a tabela que você está inserindo. As linhas são lidas primeiro e depois inseridas.