Il INSERT
inserirà solo tutte le righe e niente accadrà speciale, a meno che hai una sorta di vincolo non consentire valori duplicati/sovrapposti (PRIMARY KEY
, UNIQUE
, CHECK
o EXCLUDE
vincolo) - che non hai menzionato nella tua domanda. Ma è di questo che probabilmente sei preoccupato.
Assumendo un UNIQUE
o vincolo PK su (col1,col2)
, hai a che fare con un libro di testo UPSERT
situazione. Molte domande e risposte correlate da trovare qui.
In genere, se qualsiasi vincolo viene violato, viene sollevata un'eccezione che (a meno che non sia intrappolata in una sottotransazione come è possibile in un linguaggio procedurale lato server come plpgsql) eseguirà il rollback non solo dell'istruzione, ma dell'intera transazione .
Senza scritture simultanee
Ad esempio:nessun'altra transazione tenterà di scrivere nella stessa tabella contemporaneamente.
-
Escludi le righe che sono già nella tabella con
WHERE NOT EXISTS ...
o qualsiasi altra tecnica applicabile: -
Seleziona le righe che non sono presenti in un'altra tabella
-
E non dimenticare di rimuovere i duplicati all'interno anche il set inserito, che non essere escluso dal semi-anti-join
WHERE NOT EXISTS ...
Una tecnica per gestire entrambi contemporaneamente sarebbe 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
senza la parola chiave ALL
piega le righe duplicate nell'origine. Se sai che non ci sono duplicati, o non vuoi piegare i duplicati in silenzio, usa EXCEPT ALL
(o una delle altre tecniche). Vedi:
- Utilizzo della clausola EXCEPT in PostgreSQL
In genere, se la tabella di destinazione è grande , WHERE NOT EXISTS
in combinazione con DISTINCT
sulla sorgente sarà probabilmente più veloce:
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
);
Se possono esserci molti duplicati, vale la pena piegarli prima nella fonte. Altrimenti usa una sottoquery in meno.
Correlati:
- Seleziona le righe che non sono presenti in un'altra tabella
Con scritture simultanee
Usa il UPSERT
di Postgres implementazione INSERT ... ON CONFLICT ...
in Postgres 9.5 o successivo:
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!
Ulteriori letture:
- Come utilizzare RETURNING con ON CONFLICT in PostgreSQL?
- Come faccio a inserire una riga che contiene una chiave esterna?
Documentazione:
- Il manuale
- La pagina del commit
- La pagina Wiki di Postgres
Risposta di riferimento di Craig per UPSERT
problemi:
- Come eseguire l'UPSERT (MERGE, INSERT ... ON DUPLICATE UPDATE) in PostgreSQL?