Solusi dalam satu pernyataan SQL. Memerlukan PostgreSQL 8.4 atau lebih baru.
Pertimbangkan demo berikut:
Penyiapan pengujian:
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');
Perintah INSERT / SELECT:
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;
-
CTE v pertama tidak sepenuhnya diperlukan, tetapi untuk mencapainya Anda harus memasukkan nilai hanya sekali.
-
Pilihan CTE kedua
id
daritbl
jika "baris" itu ada. -
CTE ketiga yang saya masukkan "baris" menjadi
tbl
jika (dan hanya jika) tidak ada, kembalikanid
. -
SELECT
final terakhir mengembalikanid
. Saya menambahkan kolomsrc
menunjukkan "sumber" - apakah "baris" sudah ada sebelumnya danid
berasal dari SELECT, atau "baris" baru dan begitu jugaid
. -
Versi ini harus secepat mungkin karena tidak memerlukan SELECT tambahan dari
tbl
dan menggunakan CTE sebagai gantinya.
Untuk membuat ini aman dari kemungkinan kondisi balapan di lingkungan multi-pengguna:
Juga untuk teknik yang diperbarui menggunakan UPSERT baru di Postgres 9.5 atau lebih baru:
- Apakah SELECT atau INSERT dalam fungsi rentan terhadap kondisi balapan?