Versione finale
... dopo qualche informazione in più da OP. Considera questa demo:
-- 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)
);
Inserisci valori - bar
primo.
Sarebbe molto utile se hai fornito i dati del test nella tua domanda in questo modo!
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);
Imposta le sequenze sui valori correnti o otteniamo violazioni delle chiavi duplicate:
SELECT setval('foo_id_seq', 3);
SELECT setval('bar_id_seq', 102);
Controlli:
-- SELECT nextval('foo_id_seq')
-- SELECT nextval('bar_id_seq')
-- SELECT * from bar;
-- SELECT * from foo;
Domanda:
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);
Questo dovrebbe fare ciò che descrive il tuo ultimo aggiornamento.
La query presuppone che z
è UNIQUE
. Se z
non è unico, diventa più complesso. Fare riferimento alla query 2 in questa risposta correlata per una soluzione pronta utilizzando la funzione della finestra row_number()
in questo caso.
Inoltre, considera la possibilità di sostituire la relazione 1:1 tra foo
e bar
con un unico tavolo unito.
Modifica dati CTE
Seconda risposta dopo maggiori informazioni.
Se vuoi aggiungere righe a foo
e bar
in una singola query, puoi utilizzare un CTE di modifica dei dati a partire da 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;
Traggo valori da foo
, inseriscili in bar
, falli restituire insieme a un bar_id
generato automaticamente e inserisci quello in foo
. Puoi utilizzare anche qualsiasi altro dato.
Ecco una demo funzionante con cui giocare su sqlfiddle.
Nozioni di base
Risposta originale con informazioni di base prima dei chiarimenti.
Il modulo di base è:
INSERT INTO foo (...)
SELECT ... FROM foo WHERE ...
Nessuna parentesi necessaria. Puoi fare lo stesso con qualsiasi tabella
INSERT INTO foo (...)
SELECT ... FROM bar WHERE ...
E puoi unirti al tavolo in cui inserisci in 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
È solo un SELECT come un altro, che può includere la tabella in cui stai inserendo. Le righe vengono prima lette, quindi inserite.