I have two tables of the following form (i.e., every foo is linked to exactly one bar).
CREATE TABLE foo (
id INTEGER PRIMARY KEY,
x INTEGER NOT NULL,
y INTEGER NOT NULL,
...,
bar_id INTEGER UNIQUE NOT NULL,
FOREIGN key (bar_id) REFERENCES bar(id)
);
CREATE TABLE bar (
id INTEGER PRIMARY KEY,
z INTEGER NOT NULL,
...
);
It’s easy to copy rows in foo which meet a particular condition using a nested query:
INSERT INTO foo (...) (SELECT ... FROM foo WHERE ...)
But I can’t figure out how to make a copy of the associated row in bar for each row in foo and insert the id of bar into the new foo row. Is there any way of doing this in a single query?
Concrete example of desired result:
-- Before query:
foo(id=1,x=3,y=4,bar_id=100) ..... bar(id=100,z=7)
foo(id=2,x=9,y=6,bar_id=101) ..... bar(id=101,z=16)
foo(id=3,x=18,y=0,bar_id=102) ..... bar(id=102,z=21)
-- Query copies all pairs of foo/bar rows for which x>3:
-- Originals
foo(id=1,x=3,y=4,bar_id=101) ..... bar(id=101,z=7)
foo(id=2,x=9,y=6,bar_id=102) ..... bar(id=102,z=16)
foo(id=3,x=18,y=0,bar_id=103) ..... bar(id=103,z=21)
-- "Copies" of foo(id=2,...) and foo(id=3,...), with matching copies of
-- bar(id=102,...) and bar(id=103,...)
foo(id=4,x=9,y=6,bar_id=104) ..... bar(id=104,z=16)
foo(id=5,x=18,y=0,bar_id=105) ..... bar(id=105,z=21)
Final version
… after some more info from OP. Consider this demo:
Insert values –
barfirst.Test data like this would be very helpful in your question:
Set sequences to current values or we get duplicate key violations:
Checks:
Query:
This should do what your last update describes.
The query assumes that
zisUNIQUE. Ifzis not unique, it gets more complex. Refer to Query 2 in this related answer for a ready solution using the window functionrow_number()in this case.Also, consider replacing the 1:1 relation between
fooandbarwith a single united table.Data modifying CTE
Second answer after more info.
If you want to add rows to
fooandbarin a single query, you can use a data modifying CTE since PostgreSQL 9.1:I take values from
foo, insert them inbar, have them returned together with an auto-generatedbar_idand insert that intofoo. You can use any other data, too.Here is a working demo to play with on sqlfiddle.
Basics
Original answer with basic information before clarifications.
The basic form is:
No parenthesis needed.
You can do the same with any table
And you can join to the table you insert into in the SELECT:
It’s just a
SELECTlike any other – that can include the table you are inserting into. The rows are first read, and then inserted.