PostgreSQL INSERT ON CONFLICT UPDATE (upsert) utilise toutes les valeurs exclues


142

Lorsque vous insérez une ligne (PostgreSQL> = 9.5), et que vous voulez que le possible INSERT soit exactement le même que le possible UPDATE, vous pouvez l'écrire comme ceci:

INSERT INTO tablename (id, username, password, level, email) 
                VALUES (1, 'John', 'qwerty', 5, 'john@mail.com') 
ON CONFLICT (id) DO UPDATE SET 
  id=EXCLUDED.id, username=EXCLUDED.username,
  password=EXCLUDED.password, level=EXCLUDED.level,email=EXCLUDED.email

Y a-t-il un moyen plus court? Pour dire simplement: utilisez toutes les valeurs EXCLUDE.

Dans SQLite, je faisais:

INSERT OR REPLACE INTO tablename (id, user, password, level, email) 
                        VALUES (1, 'John', 'qwerty', 5, 'john@mail.com')

43
Pas une vraie réponse mais vous pouvez utiliser une notation un peu brève: INSERT INTO tablename (id, username, password, level, email) VALUES (1, 'John', 'qwerty', 5, 'john@mail.com') ON CONFLICT (id) DO UPDATE SET (username, password, level, email) = (EXCLUDED.username, EXCLUDED.password, EXCLUDED.level, EXCLUDED.email).presque la même chose, mais facile à copier / coller / gérer la liste des colonnes
poulain

Une autre option est d'utiliser des colonnes jsonb et de cette façon, vous n'avez pas à vous soucier des colonnes
j sera le

Réponses:


162

Postgres n'a pas implémenté d'équivalent à INSERT OR REPLACE. Extrait de la ON CONFLICTdocumentation (c'est moi qui souligne):

Il peut s'agir soit de DO NOTHING, soit d'une clause DO UPDATE spécifiant les détails exacts de l'action UPDATE à effectuer en cas de conflit.

Bien que cela ne vous donne pas de raccourci pour le remplacement, ON CONFLICT DO UPDATEs'applique plus généralement, car il vous permet de définir de nouvelles valeurs en fonction de données préexistantes. Par exemple:

INSERT INTO users (id, level)
VALUES (1, 0)
ON CONFLICT (id) DO UPDATE
SET level = users.level + 1;

3
Par prudence, le "on update" n'est pas sémantiquement identique au "merge" du standard SQL, bien qu'il puisse généralement être utilisé aux mêmes endroits. J'ai eu un cas où je m'attendais à ce que la «mise à jour en conflit» démarre, mais le problème exact dans l'insert n'a pas provoqué le déclenchement de la mise à jour (qui aurait réparé l'enregistrement endommagé).
pojo-guy

2
Pouvez-vous développer "mais le problème exact dans l'insert n'a pas provoqué la mise à jour"?
MrR

@ pojo-guy - Je ne pense pas que vous ayez vu la question de MrR - Pouvez-vous développer "mais le problème exact dans l'insert n'a pas causé la mise à jour"?
Randall

Lorsque vous essayez d'utiliser insert ... on update dans postgresql, les résultats sont différents dans certaines circonstances spécifiques à une fusion. Le cas que j'ai rencontré était plutôt obscur et spécifique, mais il était répétable. Cela fait quelques mois, donc je ne peux plus donner plus maintenant.
pojo-guy

Ce n'était peut-être pas un conflit mais une autre erreur, par exemple une erreur de type de champ?
MrR
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.