sql >> Databasteknik >  >> RDS >> PostgreSQL

Vad händer med dubbletter när du infogar flera rader?

INSERT kommer bara att infoga alla rader och ingenting speciell kommer att hända, om inte du har någon form av begränsning inte tillåta dubbletter/överlappande värden (PRIMARY KEY , UNIQUE , CHECK eller EXCLUDE constraint) - som du inte nämnde i din fråga. Men det är det du förmodligen är orolig för.

Förutsatt en UNIQUE eller PK-begränsning på (col1,col2) , du har att göra med en lärobok UPSERT situation. Många relaterade frågor och svar hittar du här.

I allmänhet, om någon begränsningen överträds, ett undantag tas upp som (såvida det inte är instängt i deltransaktion som det är möjligt i ett procedurspråk på serversidan som plpgsql) kommer att rulla tillbaka inte bara uttalandet utan hela transaktionen .

Utan samtidiga skrivningar

Dvs:Inga andra transaktioner kommer att försöka skriva till samma tabell samtidigt.

  • Exkludera rader som redan finns i tabellen med WHERE NOT EXISTS ... eller någon annan tillämplig teknik:

  • Välj rader som inte finns i andra tabeller

  • Och glöm inte att ta bort dubbletter inom den infogade uppsättningen också, vilket inte skulle göra uteslutas av semi-anti-join WHERE NOT EXISTS ...

En teknik för att hantera båda samtidigt skulle vara 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 utan nyckelordet ALL viker dubblettrader i källan. Om du vet att det inte finns några duper, eller om du inte vill vika dubbletter tyst, använd EXCEPT ALL (eller någon av de andra teknikerna). Se:

  • Använder EXCEPT-satsen i PostgreSQL

I allmänhet, om måltabellen är stor , WHERE NOT EXISTS i kombination med DISTINCT på källan kommer förmodligen att vara snabbare:

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

Kan det bli många duper lönar det sig att vika in dem i källan först. Använd annars en underfråga mindre.

Relaterat:

  • Välj rader som inte finns i andra tabeller

Med samtidiga skrivningar

Använd Postgres UPSERT implementering INSERT ... ON CONFLICT ... i Postgres 9.5 eller senare:

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!

Mer läsning:

  • Hur använder man RETURNING med ON CONFLICT i PostgreSQL?
  • Hur infogar jag en rad som innehåller en främmande nyckel?

Dokumentation:

  • Handboken
  • Bekräftelsesidan
  • Postgres Wiki-sida

Craigs referenssvar för UPSERT problem:

  • Hur UPSERT (SLÄNTA, INFOGA ... PÅ DUBLIKAT UPPDATERING) i PostgreSQL?


  1. VÄNSTER JOIN endast första raden

  2. Välj första raden i varje GROUP BY-grupp?

  3. Hur får man tillgång till Oracle-databasen över nätverket?

  4. MS Access anropar SQL Server lagrad procedur