Le INSERT
va simplement insérer toutes les lignes et rien spécial se produira, à moins que vous avez une sorte de contrainte interdire les valeurs en double/qui se chevauchent (PRIMARY KEY
, UNIQUE
, CHECK
ou EXCLUDE
contrainte) - que vous n'avez pas mentionné dans votre question. Mais c'est probablement ce qui vous inquiète.
En supposant un UNIQUE
ou contrainte PK sur (col1,col2)
, vous avez affaire à un manuel UPSERT
situation. De nombreuses questions et réponses connexes à trouver ici.
Généralement, si tout contrainte est violée, une exception est levée qui (à moins qu'elle ne soit piégée dans une sous-transaction comme c'est possible dans un langage procédural côté serveur comme plpgsql) annulera non seulement la déclaration, mais la transaction entière .
Sans écritures simultanées
C'est-à-dire :aucune autre transaction n'essaiera d'écrire dans la même table en même temps.
-
Exclure les lignes qui sont déjà dans le tableau avec
WHERE NOT EXISTS ...
ou toute autre technique applicable : -
Sélectionnez les lignes qui ne sont pas présentes dans un autre tableau
-
Et n'oubliez pas de supprimer les doublons dans l'ensemble inséré également, ce qui ne serait pas être exclu par la semi-anti-jointure
WHERE NOT EXISTS ...
Une technique pour gérer les deux à la fois serait 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
sans le mot clé ALL
plie les lignes en double dans la source. Si vous savez qu'il n'y a pas de doublons, ou si vous ne voulez pas plier les doublons en silence, utilisez EXCEPT ALL
(ou l'une des autres techniques). Voir :
- Utilisation de la clause EXCEPT dans PostgreSQL
Généralement, si la table cible est grande , WHERE NOT EXISTS
en combinaison avec DISTINCT
sur la source sera probablement plus rapide :
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
);
S'il peut y avoir de nombreuses dupes, il est avantageux de les intégrer d'abord à la source. Sinon, utilisez une sous-requête de moins.
Connexe :
- Sélectionnez les lignes qui ne sont pas présentes dans un autre tableau
Avec écritures simultanées
Utilisez Postgres UPSERT
implémentation INSERT ... ON CONFLICT ...
dans Postgres 9.5 ou plus tard :
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!
Lectures complémentaires :
- Comment utiliser RETURNING avec ON CONFLICT dans PostgreSQL ?
- Comment insérer une ligne contenant une clé étrangère ?
Documents :
- Le manuel
- La page de validation
- La page Wiki de Postgres
Réponse de référence de Craig pour UPSERT
problèmes :
- Comment UPSERT (MERGE, INSERT ... ON DUPLICATE UPDATE) dans PostgreSQL ?