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, '[email protected]') 
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, '[email protected]')
Sébastien
la source
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, '[email protected]') 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;
Kristján
la source
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