PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Restituire id se esiste una riga, INSERT in caso contrario

Una soluzione in un'unica istruzione SQL. Richiede PostgreSQL 8.4 o versioni successive.
Considera la seguente demo:

Configurazione di prova:

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');

INSERIRE / SELEZIONA comando:

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;
  • Il primo CTE v non è strettamente necessario, ma realizza che devi inserire i tuoi valori solo una volta.

  • La seconda seleziona CTE s l'id da tbl se la "riga" esiste.

  • Il terzo Inserimento CTE i la "riga" in tbl se (e solo se) non esiste, restituendo id .

  • Il SELECT finale restituisce l'id . Ho aggiunto una colonna src indicando la "fonte" - se la "riga" preesisteva e id viene da un SELECT, oppure la "riga" era nuova, così come l'id .

  • Questa versione dovrebbe essere il più veloce possibile in quanto non necessita di un ulteriore SELECT da tbl e utilizza invece i CTE.

Per renderlo sicuro contro possibili condizioni di gara in un ambiente multiutente:
Anche per le tecniche aggiornate utilizzando il nuovo UPSERT in Postgres 9.5 o successivo:

  • SELEZIONA o INSERT in una funzione soggetta a condizioni di gara?