L'implémentation UPSERT est extrêmement complexe pour être protégée contre les accès en écriture simultanés. Jetez un œil à ce wiki Postgres qui a servi de journal lors du développement initial. Les pirates de Postgres ont décidé de ne pas inclure les lignes "exclues" dans le RETURNING
clause pour la première version de Postgres 9.5. Ils pourraient créer quelque chose pour la prochaine version.
Voici l'énoncé crucial du manuel pour expliquer votre situation :
La syntaxe du
RETURNING
la liste est identique à celle de la liste de sortie deSELECT
. Seules les lignes insérées ou mises à jour avec succès seront renvoyées. Par exemple, si une ligne a été verrouillée mais pas mise à jour en raison d'unON CONFLICT DO UPDATE ... WHERE
la condition de la clause n'était pas satisfaite, la ligne ne sera pas renvoyée.
J'insiste sur moi.
Pour une ligne unique pour insérer :
Sans charge d'écriture simultanée sur la même table
WITH ins AS (
INSERT INTO users(name)
VALUES ('new_usr_name') -- input value
ON CONFLICT(name) DO NOTHING
RETURNING users.id
)
SELECT id FROM ins
UNION ALL
SELECT id FROM users -- 2nd SELECT never executed if INSERT successful
WHERE name = 'new_usr_name' -- input value a 2nd time
LIMIT 1;
Avec une charge d'écriture simultanée possible sur la table
Considérez ceci à la place (pour une seule ligne INSERT
):
- SELECT ou INSERT est-il dans une fonction sujette à des conditions de concurrence ?
Pour insérer un ensemble de lignes :
-
Comment utiliser RETURNING avec ON CONFLICT dans PostgreSQL ?
-
Comment inclure des lignes exclues dans RETURNING from INSERT ... ON CONFLICT
Tous les trois avec des explications très détaillées.