Certains serveurs SQL ont une fonctionnalité qui INSERT
est ignorée si elle enfreint une contrainte de clé primaire / unique. Par exemple, MySQL a INSERT IGNORE
.
Quelle est la meilleure façon d'émuler INSERT IGNORE
et ON DUPLICATE KEY UPDATE
avec PostgreSQL?
database
postgresql
rules
gpilotino
la source
la source
ON DUPLICATE KEY UPDATE
sur PgSQL 9.5 est encore quelque peu impossible, car l'ON CLAUSE
équivalent de PgSQL vous oblige à fournir le nom de la contrainte, tandis que MySQL pourrait capturer n'importe quelle contrainte sans avoir besoin de la définir. Cela m'empêche «d'émuler» cette fonctionnalité sans réécrire les requêtes.Réponses:
Essayez de faire une MISE À JOUR. S'il ne modifie aucune ligne, cela signifie qu'il n'existe pas, alors faites une insertion. Évidemment, vous faites cela dans une transaction.
Vous pouvez bien sûr envelopper cela dans une fonction si vous ne voulez pas mettre le code supplémentaire côté client. Vous avez également besoin d'une boucle pour la condition de course très rare dans cette réflexion.
Il y a un exemple de cela dans la documentation: http://www.postgresql.org/docs/9.3/static/plpgsql-control-structures.html , exemple 40-2 en bas.
C'est généralement le moyen le plus simple. Vous pouvez faire de la magie avec des règles, mais ce sera probablement beaucoup plus compliqué. Je recommanderais l'approche de la fonction enveloppante à tout moment.
Cela fonctionne pour les valeurs d'une seule ligne ou de quelques lignes. Si vous avez affaire à de grandes quantités de lignes, par exemple à partir d'une sous-requête, il est préférable de la diviser en deux requêtes, une pour INSERT et une pour UPDATE (comme une jointure / sous-sélection appropriée bien sûr - pas besoin d'écrire votre main filtrer deux fois)
la source
INSERT ... ON CONFLICT DO NOTHING;
. Voir également la réponse stackoverflow.com/a/34639631/2091700 .MERGE
n'est pas un upsert sécurisé pour l'accès concurrentiel, sauf si vous prenez unLOCK TABLE
premier. Les gens l'utilisent de cette façon, mais c'est faux.Avec PostgreSQL 9.5, il s'agit désormais d' une fonctionnalité native (comme MySQL l'a depuis plusieurs années):
...
la source
Edit: au cas où vous auriez manqué la réponse de warren , PG9.5 l'a maintenant nativement; il est temps de mettre à niveau!
S'appuyant sur la réponse de Bill Karwin, pour expliquer à quoi ressemblerait une approche basée sur des règles (transfert d'un autre schéma dans la même base de données et avec une clé primaire à plusieurs colonnes):
Remarque: la règle s'applique à toutes les
INSERT
opérations jusqu'à ce que la règle soit supprimée, donc pas tout à fait ad hoc.la source
another_schema.my_table
contient des doublons selon les contraintes demy_table
?INSERT INTO "my_table" SELECT DISTINCT ON (pk_col_1, pk_col_2) * FROM the_tmp_table;
DELETE FROM my_table WHERE ctid IN (SELECT ctid FROM (SELECT ctid,ROW_NUMBER() OVER (PARTITION BY pk_col_1,pk_col_2) AS rn FROM my_table) AS dups WHERE dups.rn > 1);
Pour ceux d'entre vous qui ont Postgres 9.5 ou supérieur, la nouvelle syntaxe ON CONFLICT DO NOTHING devrait fonctionner:
Pour ceux d'entre nous qui ont une version antérieure, cette jointure droite fonctionnera à la place:
la source
Unique violation: 7 ERROR: duplicate key value violates unique constraint
quand unetarget_table
autre ligne a été insérée pendant l' exécution de cette requête, si leurs clés se dupliquent effectivement. Je pense que le verrouillagetarget_table
aidera, mais la concurrence en souffrira évidemment.ON CONFLICT (field_one) DO NOTHING
est la meilleure partie de la réponse.Pour obtenir la logique d' insertion ignorée , vous pouvez faire quelque chose comme ci-dessous. J'ai trouvé que l'insertion à partir d'une instruction de sélection de valeurs littérales fonctionnait mieux, puis vous pouvez masquer les clés en double avec une clause NOT EXISTS. Pour obtenir la mise à jour sur la logique dupliquée, je soupçonne qu'une boucle pl / pgsql serait nécessaire.
la source
la source
On dirait que PostgreSQL prend en charge un objet de schéma appelé règle .
http://www.postgresql.org/docs/current/static/rules-update.html
Vous pouvez créer une règle
ON INSERT
pour une table donnée, en la faisant faireNOTHING
si une ligne existe avec la valeur de clé primaire donnée, ou bien en la faisant faire uneUPDATE
au lieu deINSERT
si une ligne existe avec la valeur de clé primaire donnée.Je n'ai pas essayé cela moi-même, donc je ne peux pas parler d'expérience ou donner un exemple.
la source
Comme @hanmari l'a mentionné dans son commentaire. lors de l'insertion dans une table postgres, on conflict (..) do Nothing est le meilleur code à utiliser pour ne pas insérer de données en double:
La ligne de code ON CONFLICT permettra à l'instruction d'insertion d'insérer toujours des lignes de données. Le code de requête et de valeurs est un exemple de date insérée depuis un Excel dans une table de base de données postgres. J'ai des contraintes ajoutées à une table postgres que j'utilise pour m'assurer que le champ ID est unique. Au lieu d'exécuter une suppression sur des lignes de données identiques, j'ajoute une ligne de code sql qui renumérote la colonne ID à partir de 1. Exemple:
Si mes données ont un champ ID, je ne l'utilise pas comme ID principal / ID de série, je crée une colonne ID et je la mets en série. J'espère que ces informations seront utiles à tout le monde. * Je n'ai pas de diplôme universitaire en développement / codage de logiciels. Tout ce que je sais en codage, je l'étudie seul.
la source
Cette solution évite d'utiliser des règles:
mais il a un inconvénient en termes de performances (voir PostgreSQL.org ):
la source
En bloc, vous pouvez toujours supprimer la ligne avant l'insertion. La suppression d'une ligne qui n'existe pas ne provoque pas d'erreur, elle est donc ignorée en toute sécurité.
la source
DEFERRABLE INITIALLY DEFERRED
indicateurs.Pour les scripts d'importation de données, pour remplacer "IF NOT EXISTS", d'une certaine manière, il existe une formulation un peu maladroite qui fonctionne néanmoins:
la source