sql >> Databasteknik >  >> RDS >> PostgreSQL

Returnera id om en rad finns, INSERT annars

En lösning i en enda SQL-sats. Kräver PostgreSQL 8.4 eller senare dock.
Tänk på följande demo:

Testinställningar:

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

INSERT / SELECT kommando:

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;
  • Den första CTE v är inte strikt nödvändigt, men uppnår att du måste ange dina värden bara en gång.

  • Den andra CTE s väljer id från tbl om "raden" finns.

  • Den tredje CTE i infogar "raden" till tbl om (och bara om) det inte finns, returnerar id .

  • Den sista SELECT returnerar id . Jag lade till en kolumn src anger "källan" - om "raden" existerade och id kommer från en SELECT, eller så var "raden" ny och så är id .

  • Denna version bör vara så snabb som möjligt eftersom den inte behöver en extra SELECT från tbl och använder CTE istället.

För att göra detta säkert mot möjliga tävlingsförhållanden i en miljö med flera användare:
Också för uppdaterade tekniker med den nya UPSERT i Postgres 9.5 eller senare:

  • Är SELECT eller INSERT i en funktion utsatt för tävlingsförhållanden?


  1. SQL:Vad är standardordningen efter för frågor?

  2. SQLite-gräns

  3. Hur Extract() fungerar i PostgreSQL

  4. Använder parameter som kolumnnamn i Postgres-funktionen