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

Hvad sker der med dubletter, når der indsættes flere rækker?

INSERT vil bare indsætte alle rækker og ingenting særlige vil ske, medmindre du har en form for begrænsning ikke tillade duplikerede/overlappende værdier (PRIMARY KEY , UNIQUE , CHECK eller EXCLUDE constraint) - som du ikke nævnte i dit spørgsmål. Men det er du sikkert bekymret over.

Forudsat en UNIQUE eller PK-begrænsning på (col1,col2) , du har at gøre med en lærebog UPSERT situation. Mange relaterede spørgsmål og svar at finde her.

Generelt, hvis nogen begrænsning er overtrådt, er der rejst en undtagelse, som (medmindre fanget i subtransaktion som det er muligt i et proceduremæssigt server-side sprog som plpgsql) vil rulle tilbage ikke kun erklæringen, men hele transaktionen .

Uden samtidige skrivninger

Dvs.:Ingen andre transaktioner vil forsøge at skrive til den samme tabel på samme tid.

  • Ekskluder rækker, der allerede er i tabellen med WHERE NOT EXISTS ... eller enhver anden anvendelig teknik:

  • Vælg rækker, der ikke er til stede i anden tabel

  • Og glem ikke at fjerne dubletter indenfor det indsatte sæt også, hvilket ikke ville blive udelukket af semi-anti-join WHERE NOT EXISTS ...

En teknik til at håndtere begge dele på én gang ville være EXCEPT :

INSERT INTO tbl (col1, col2)
VALUES
  (text 'v1', text 'v2')  -- explicit type cast may be needed in 1st row
, ('v3', 'v4')
, ('v3', 'v4')  -- beware of dupes in source
EXCEPT SELECT col1, col2 FROM tbl;

EXCEPT uden nøgleordet ALL folder duplikerede rækker i kilden. Hvis du ved, at der ikke er nogen duplikater, eller du ikke ønsker at folde dubletter stille, skal du bruge EXCEPT ALL (eller en af ​​de andre teknikker). Se:

  • Ved brug af EXCEPT-sætning i PostgreSQL

Generelt, hvis måltabellen er stor , WHERE NOT EXISTS i kombination med DISTINCT på kilden vil sandsynligvis være hurtigere:

INSERT INTO tbl (col1, col2)
SELECT *
FROM  (
   SELECT DISTINCT *
   FROM  (
       VALUES
         (text 'v1', text'v2')
       , ('v3', 'v4')
       , ('v3', 'v4')  -- dupes in source
      ) t(c1, c2)
   ) t
WHERE NOT EXISTS (
   SELECT FROM tbl
   WHERE  col1 = t.c1 AND col2 = t.c2
   );

Hvis der kan være mange duper, kan det betale sig at folde dem i kilden først. Ellers brug en underforespørgsel mindre.

Relateret:

  • Vælg rækker, der ikke findes i en anden tabel

Med samtidig skrivning

Brug Postgres UPSERT implementering INSERT ... ON CONFLICT ... i Postgres 9.5 eller senere:

INSERT INTO tbl (col1,col2)
SELECT DISTINCT *  -- still can't insert the same row more than once
FROM  (
   VALUES
     (text 'v1', text 'v2')
   , ('v3','v4')
   , ('v3','v4')  -- you still need to fold dupes in source!
  ) t(c1, c2)
ON CONFLICT DO NOTHING;  -- ignores rows with *any* conflict!

Yderligere læsning:

  • Hvordan bruger man RETURNING med ON CONFLICT i PostgreSQL?
  • Hvordan indsætter jeg en række, der indeholder en fremmednøgle?

Dokumentation:

  • Manualen
  • Forpligtelsessiden
  • Postgres Wiki-siden

Craigs referencesvar for UPSERT problemer:

  • Hvordan UPSERT (FLETT, INDSÆT ... VED DUPLIKAT OPDATERING) i PostgreSQL?


  1. Kopier tabel til en anden database på en anden SQL Server

  2. Introduktion til MaxScale Administration Brug af maxctrl til MariaDB Cluster

  3. Oprettelse af en bruger på MySQL

  4. OPDATERING med CASE og IN - Oracle