Slutlig version
... efter lite mer info från OP. Tänk på den här demon:
-- 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)
);
Infoga värden - bar
först.
Det skulle vara mycket nyttigt om du angav testdata i din fråga så här!
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);
Ställ in sekvenser till aktuella värden eller så får vi dubbletter av nyckelöverträdelser:
SELECT setval('foo_id_seq', 3);
SELECT setval('bar_id_seq', 102);
Kontroller:
-- SELECT nextval('foo_id_seq')
-- SELECT nextval('bar_id_seq')
-- SELECT * from bar;
-- SELECT * from foo;
Fråga:
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);
Detta bör göra vad din senaste uppdatering beskriver.
Frågan förutsätter att z
är UNIQUE
. Om z
är inte unikt, det blir mer komplext. Se fråga 2 i detta relaterade svar för en färdig lösning med fönsterfunktionen row_number()
i det här fallet.
Överväg också att ersätta 1:1-relationen mellan foo
och bar
med ett enda förenat bord.
Datamodifierande CTE
Andra svaret efter mer info.
Om du vill lägga till rader till foo
och bar
i en enda fråga kan du använda en datamodifierande CTE sedan 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;
Jag hämtar värden från foo
, infoga dem i bar
, få dem att returneras tillsammans med ett automatiskt genererat bar_id
och infoga det till foo
. Du kan också använda vilken annan data som helst.
Här är en fungerande demo att spela med på sqlfiddle.
Grunderna
Originalsvar med grundläggande information före förtydliganden.
Grundformuläret är:
INSERT INTO foo (...)
SELECT ... FROM foo WHERE ...
Ingen parentes behövs. Du kan göra samma sak med vilken tabell som helst
INSERT INTO foo (...)
SELECT ... FROM bar WHERE ...
Och du kan gå med i tabellen du infogar i i 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
Det är bara en SELECT som alla andra - som kan inkludera tabellen du infogar i. Raderna läses först och infogas sedan.