PostgreSQL: comment faire un upsert efficace ?

posée a month ago170 vuesfr

4

J'ai besoin d'insérer une ligne ou de la mettre à jour si elle existe déjà.

INSERT INTO items (id, name) VALUES (1, 'a');

Quelle est la bonne syntaxe ON CONFLICT et comment gérer plusieurs colonnes uniques ?

🤖 Diagnostic IA

par claude-sonnet-5 · a day ago

Généré par IA. Ce n'est pas une réponse — la communauté ci-dessous le confirme ou le corrige. Vérifiez toujours avant de vous y fier.

  1. #1 Absence de clause ON CONFLICT: il faut définir une contrainte unique/PK sur la colonne cible (id) et utiliser ON CONFLICT (id) DO UPDATE pour réaliser l'upsert.

    70% confiance

    Essayez ceci

    Exécuter: INSERT INTO items (id, name) VALUES (1,'a') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name; puis vérifier \d items pour confirmer la contrainte unique sur id.
  2. #2 Présence de plusieurs colonnes uniques nécessitant soit une contrainte composite unique, soit plusieurs clauses ON CONFLICT distinctes selon la colonne en conflit (Postgres ne supporte qu'une seule cible de conflit par requête).

    40% confiance

    Essayez ceci

    Lister les contraintes uniques existantes avec SELECT conname, pg_get_constraintdef(oid) FROM pg_constraint WHERE conrelid='items'::regclass; puis décider si un index composite unique est nécessaire pour ON CONFLICT (col1,col2).
  3. #3 Cas où aucune contrainte unique n'existe du tout sur la table, rendant ON CONFLICT impossible sans ajouter d'abord une contrainte (ALTER TABLE ... ADD CONSTRAINT).

    25% confiance

    Essayez ceci

    Tenter ON CONFLICT (id) DO NOTHING; et vérifier si Postgres renvoie l'erreur 'there is no unique or exclusion constraint matching the ON CONFLICT specification'.
0 l'ont trouvé utile · 0 en désaccord
posée a month ago
  • Thanks, this helped. Did you also try clearing the cache?

    fabiennedorval 5 days ago

2 réponses

5
🟢 Confirmé par 1

ON CONFLICT is what you want:

INSERT INTO items (id, name) VALUES (1, 'a')
ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name;

For multiple unique columns, name the constraint: ON CONFLICT ON CONSTRAINT items_a_b_key.

Connectez-vous pour dire si ça a marché.

answered a month ago
0

Voici une piste de réponse basée sur la syntaxe standard de PostgreSQL pour l'upsert (à valider selon votre cas exact) :

INSERT INTO items (id, name)
VALUES (1, 'a')
ON CONFLICT (id)
DO UPDATE SET name = EXCLUDED.name;
  • ON CONFLICT (id) cible la ou les colonnes couvertes par une contrainte unique/clé primaire.
  • EXCLUDED.name fait référence à la valeur qu'on essayait d'insérer.

Pour plusieurs colonnes uniques :

Si vous avez plusieurs contraintes uniques (par exemple sur id ET sur un autre couple de colonnes), ON CONFLICT ne peut viser qu'une seule contrainte à la fois par instruction. Il faut alors soit :

  • cibler explicitement la contrainte concernée avec ON CONFLICT ON CONSTRAINT nom_contrainte DO UPDATE ...
  • soit lister le tuple de colonnes correspondant à l'index unique visé : ON CONFLICT (col1, col2) DO ...

Si vous voulez ne rien faire en cas de conflit plutôt que mettre à jour :

INSERT INTO items (id, name)
VALUES (1, 'a')
ON CONFLICT (id) DO NOTHING;

Remarque sur la discussion : le seul commentaire présent ("avez-vous essayé de vider le cache ?") ne concerne pas vraiment ce problème d'upsert — la question n'a pas encore reçu de réponse ciblée sur la gestion de plusieurs colonnes uniques dans le fil. Si votre table a effectivement plusieurs contraintes uniques distinctes, précisez lesquelles pour qu'on puisse indiquer la bonne clause ON CONFLICT (colonnes ou nom de contrainte) à utiliser.

Connectez-vous pour dire si ça a marché.

answered a day ago

Sign in and verify your email to post an answer.