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

Indsæt data i 3 tabeller ad gangen ved hjælp af Postgres

Brug datamodificerende CTE'er :

WITH ins1 AS (
   INSERT INTO sample(firstname, lastname)
   VALUES ('fai55', 'shaggk')
-- ON     CONFLICT DO NOTHING         -- optional addition in Postgres 9.5+
   RETURNING id AS sample_id
   )
, ins2 AS (
   INSERT INTO sample1 (sample_id, adddetails)
   SELECT sample_id, 'ss' FROM ins1
   RETURNING user_id
   )
INSERT INTO sample2 (user_id, value)
SELECT user_id, 'ss2' FROM ins2;

Hver INSERT afhænger af den før. SELECT i stedet for VALUES sørger for, at intet er indsat i underordnede tabeller, hvis ingen række returneres fra en tidligere INSERT . (Siden Postgres 9.5+ kan du tilføje en ON CONFLICT .)
Det er også lidt kortere og hurtigere på denne måde.

Typisk er det mere bekvemt at give komplette datarækker ét sted :

WITH data(firstname, lastname, adddetails, value) AS (
   VALUES                              -- provide data here
      ('fai55', 'shaggk', 'ss', 'ss2') -- see below
    , ('fai56', 'XXaggk', 'xx', 'xx2') -- works for multiple input rows
       --  more?                      
   )
, ins1 AS (
   INSERT INTO sample (firstname, lastname)
   SELECT firstname, lastname          -- DISTINCT? see below
   FROM   data
   -- ON     CONFLICT DO NOTHING       -- UNIQUE constraint? see below
   RETURNING firstname, lastname, id AS sample_id
   )
, ins2 AS (
   INSERT INTO sample1 (sample_id, adddetails)
   SELECT ins1.sample_id, d.adddetails
   FROM   data d
   JOIN   ins1 USING (firstname, lastname)
   RETURNING sample_id, user_id
   )
INSERT INTO sample2 (user_id, value)
SELECT ins2.user_id, d.value
FROM   data d
JOIN   ins1 USING (firstname, lastname)
JOIN   ins2 USING (sample_id);

db<>spil her

Du har muligvis brug for eksplicitte typecasts i en selvstændig VALUES udtryk - i modsætning til en VALUES udtryk knyttet til en INSERT hvor datatyper er afledt fra måltabellen. Se:

  • Caster NULL-typen ved opdatering af flere rækker

Hvis flere rækker kan komme med identiske (firstname, lastname) , skal du muligvis folde dubletter for den første INSERT :

...
INSERT INTO sample (firstname, lastname)
SELECT DISTINCT firstname, lastname FROM data
...

Du kan bruge en (midlertidig) tabel som datakilde i stedet for CTE data .

Det ville nok give mening at kombinere dette med en UNIK begrænsning på (firstname, lastname) i tabellen og en ON CONFLICT klausul i forespørgslen.

Relateret:

  • Hvordan bruger man RETURNING med ON CONFLICT i PostgreSQL?
  • Er SELECT eller INSERT i en funktion, der er tilbøjelig til løbsforhold?


  1. IGNORE_DUP_KEY langsommere på klyngede indekser

  2. Sådan installeres MySQL med phpMyAdmin på Debian 7

  3. Er der en RIGTIG ydelsesforskel mellem INT og VARCHAR primære nøgler?

  4. Fejl ved indstilling af n_distinct ved hjælp af en plpgsql-variabel