Versión final
... después de más información de OP. Considere esta demostración:
-- 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)
);
Insertar valores - bar
primero.
Sería muy útil si proporcionó datos de prueba en su pregunta como esta!
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);
Establezca secuencias en los valores actuales o obtendremos infracciones de clave duplicadas:
SELECT setval('foo_id_seq', 3);
SELECT setval('bar_id_seq', 102);
Cheques:
-- SELECT nextval('foo_id_seq')
-- SELECT nextval('bar_id_seq')
-- SELECT * from bar;
-- SELECT * from foo;
Consulta:
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);
Esto debería hacer lo que describe su última actualización.
La consulta asume que z
es UNIQUE
. Si z
no es único, se vuelve más complejo. Consulte la Consulta 2 en esta respuesta relacionada para obtener una solución lista usando la función de ventana row_number()
en este caso.
Además, considere reemplazar la relación 1:1 entre foo
y bar
con una sola mesa unida.
CTE de modificación de datos
Segunda respuesta después de más información.
Si desea agregar filas a foo
y bar
en una sola consulta, puede usar un CTE de modificación de datos desde 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;
Extraigo valores de foo
, insértelos en bar
, haz que se devuelvan junto con un bar_id
generado automáticamente e inserta eso en foo
. También puede utilizar cualquier otro dato.
Aquí hay una demostración funcional para jugar en sqlfiddle.
Conceptos básicos
Respuesta original con información básica antes de aclaraciones.
La forma básica es:
INSERT INTO foo (...)
SELECT ... FROM foo WHERE ...
No se necesitan paréntesis. Puedes hacer lo mismo con cualquier tabla
INSERT INTO foo (...)
SELECT ... FROM bar WHERE ...
Y puede unirse a la tabla en la que inserta en SELECCIONAR:
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
Es solo un SELECCIONAR como cualquier otro, que puede incluir la tabla en la que está insertando. Las filas se leen primero y luego se insertan.