sql >> Database teknologi >  >> RDS >> PostgreSQL

INDSÆT rækker i flere tabeller i en enkelt forespørgsel ved at vælge fra en involveret tabel

Endelig version

... efter lidt mere info fra OP. Overvej denne 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) );

Indsæt værdier - bar først.
Det ville være meget nyttigt hvis du har angivet testdata i dit spørgsmål som dette!

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);
 

Indstil sekvenser til aktuelle værdier, ellers får vi dublerede nøgleovertrædelser:

SELECT setval('foo_id_seq', 3);
SELECT setval('bar_id_seq', 102);
 

Tjek:

-- SELECT nextval('foo_id_seq')
-- SELECT nextval('bar_id_seq')
-- SELECT * from bar;
-- SELECT * from foo;
 

Forespørgsel:

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);
 

Dette burde gøre, hvad din sidste opdatering beskriver.

Forespørgslen antager, at z er UNIQUE . Hvis z er ikke unikt, det bliver mere komplekst. Se forespørgsel 2 i dette relaterede svar for en klar løsning ved hjælp af vinduesfunktionen row_number() i dette tilfælde.

Overvej også at erstatte 1:1-relationen mellem foo og bar med et enkelt samlet bord.

Datamodificerende CTE

Andet svar efter mere info.

Hvis du vil tilføje rækker til foo og bar i en enkelt forespørgsel kan du bruge en datamodificerende CTE siden 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;
 

Jeg trækker værdier fra foo , indsæt dem i bar , få dem returneret sammen med en autogenereret bar_id og indsæt det ind i foo . Du kan også bruge alle andre data.

Her er en fungerende demo at spille med på sqlfiddle.

Grundlæggende

Originalt svar med grundlæggende oplysninger før afklaringer.
Grundformularen er:

INSERT INTO foo (...)
SELECT ... FROM foo WHERE ...
 

Ingen parentes nødvendig. Du kan gøre det samme med enhver tabel

INSERT INTO foo (...)
SELECT ... FROM bar WHERE ...
 

Og du kan tilslutte dig den tabel, du indsætter 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 er bare en SELECT som enhver anden - der kan inkludere den tabel, du indsætter i. Rækkerne læses først og indsættes derefter.



  1. Kan jeg automatisk oprette en tabel i PostgreSQL fra en csv-fil med overskrifter?

  2. Sådan fungerer Tand() i PostgreSQL

  3. Forbedrer Foreign Key forespørgselsydeevne?

  4. Arbejde med Java Data i Qlik Sense