Ответ 1
Окончательная версия
... после некоторой дополнительной информации от OP. Рассмотрим эту демонстрацию:
-- 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)
);
Сначала введите значения - bar
.
Было бы очень полезно , если бы вы предоставили тестовые данные в своем вопросе следующим образом:
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);
Устанавливать последовательности на текущие значения или мы получаем дубликаты ключевых нарушений:
SELECT setval('foo_id_seq', 3);
SELECT setval('bar_id_seq', 102);
Проверка:
-- SELECT nextval('foo_id_seq')
-- SELECT nextval('bar_id_seq')
-- SELECT * from bar;
-- SELECT * from foo;
Query:
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);
Это должно делать то, что описывает ваше последнее обновление.
В запросе предполагается, что z
UNIQUE
. Если z
не является уникальным, он становится более сложным. Обратитесь к запросу 2 в этом связанном ответе для готового решения, используя в этом случае функцию окна row_number()
.
Кроме того, рассмотрите замену отношения 1:1 между foo
и bar
единой единой таблицей.
Изменение данных CTE
Второй ответ после более подробной информации.
Если вы хотите добавить строки в foo
и bar
в одном запросе, вы можете использовать данные, изменяющие CTE, поскольку 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;
Я рисую значения из foo
, вставляю их в bar
, возвращаю их вместе с автогенерированным bar_id
и вставляем в foo
. Вы также можете использовать любые другие данные.
Ниже приведена рабочая демонстрация для работы с sqlfiddle.
Основы
Оригинальный ответ с базовой информацией до разъяснений.
Основная форма:
INSERT INTO foo (...)
SELECT ... FROM foo WHERE ...
Никаких скобок не требуется. Вы можете сделать то же самое с любой таблицей
INSERT INTO foo (...)
SELECT ... FROM bar WHERE ...
И вы можете присоединиться к таблице, которую вы вставляете в 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
Это просто SELECT, как и любой другой, который может включать в себя таблицу, в которую вы вставляете. Строки сначала считываются, а затем вставляются.