sql >> Base de Datos >  >> RDS >> PostgreSQL

Devolver id si existe una fila, INSERTAR de lo contrario

Una solución en una sola instrucción SQL. Requiere PostgreSQL 8.4 o posterior.
Considere la siguiente demostración:

Configuración de prueba:

CREATE TEMP TABLE tbl (
  id  serial PRIMARY KEY
 ,txt text   UNIQUE   -- obviously there is unique column (or set of columns)
);

INSERT INTO tbl(txt) VALUES ('one'), ('two');

Comando INSERTAR/SELECCIONAR:

WITH v AS (SELECT 'three'::text AS txt)
    ,s AS (SELECT id FROM tbl JOIN v USING (txt))
    ,i AS (
       INSERT INTO tbl (txt)
       SELECT txt
       FROM   v
       WHERE  NOT EXISTS (SELECT * FROM s)
       RETURNING id
       )
SELECT id, 'i'::text AS src FROM i
UNION  ALL
SELECT id, 's' FROM s;
  • El primer V CTE no es estrictamente necesario, pero logra que tengas que ingresar tus valores solo una vez.

  • El segundo CTE s selecciona el id de tbl si la "fila" existe.

  • El tercer CTE i inserta la "fila" en tbl si (y solo si) no existe, devolviendo id .

  • El SELECT final devuelve el id . Agregué una columna src indicando la "fuente" - si la "fila" existía previamente y id proviene de un SELECT, o la "fila" era nueva y también lo es el id .

  • Esta versión debería ser lo más rápida posible ya que no necesita un SELECT adicional de tbl y usa los CTE en su lugar.

Para que esto sea seguro contra posibles condiciones de carrera en un entorno multiusuario:
También para técnicas actualizadas usando el nuevo UPSERT en Postgres 9.5 o posterior:

  • ¿Es SELECCIONAR o INSERTAR en una función propensa a condiciones de carrera?