PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Renvoie les lignes de INSERT avec ON CONFLICT sans avoir besoin de mettre à jour

C'est le problème récurrent de SELECT or INSERT , lié à (mais différent de) un UPSERT. La nouvelle fonctionnalité UPSERT dans Postgres 9.5 est toujours essentielle.

WITH ins AS (
   INSERT INTO names(name)
   VALUES ('bob')
   ON     CONFLICT ON CONSTRAINT names_name_key DO UPDATE
   SET    name = NULL
   WHERE  FALSE      -- never executed, but locks the row
   RETURNING id
   )
SELECT id FROM ins
UNION  ALL
SELECT id FROM names
WHERE  name = 'bob'  -- only executed if no INSERT
LIMIT  1;

De cette façon, vous n'écrivez pas réellement une nouvelle version de ligne sans besoin.

Cependant , il y a encore un petit cas d'angle pour une condition de concurrence . Les transactions simultanées peuvent avoir ajouté une ligne en conflit, qui n'est pas encore visible dans la même instruction. Puis INSERT et SELECT venir vide.

Solution appropriée pour UPSERT à une seule ligne :

  • SELECT ou INSERT est-il dans une fonction sujette à des conditions de concurrence ?

Solutions générales pour UPSERT en masse :

  • Comment utiliser RETURNING avec ON CONFLICT dans PostgreSQL ?

Sans charge d'écriture simultanée

Si les écritures simultanées (à partir d'une session différente) ne sont pas possibles, vous n'avez pas besoin de verrouiller la ligne et vous pouvez simplifier :

WITH ins AS (
   INSERT INTO names(name)
   VALUES ('bob')
   ON     CONFLICT ON CONSTRAINT names_name_key DO NOTHING  -- no lock needed
   RETURNING id
   )
SELECT id FROM ins
UNION  ALL
SELECT id FROM names
WHERE  name = 'bob'  -- only executed if no INSERT
LIMIT  1;