Ini adalah masalah berulang dari SELECT or INSERT
, terkait dengan (tetapi berbeda dari) UPSERT. Fungsionalitas UPSERT baru di Postgres 9.5 masih berperan.
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;
Dengan cara ini Anda tidak benar-benar menulis versi baris baru tanpa perlu.
Namun , masih ada kotak sudut kecil untuk kondisi balapan . Transaksi bersamaan mungkin telah menambahkan baris yang bertentangan, yang belum terlihat dalam pernyataan yang sama. Kemudian INSERT
dan SELECT
kosong.
Solusi yang tepat untuk UPSERT satu baris:
- Apakah SELECT atau INSERT dalam fungsi rentan terhadap kondisi balapan?
Solusi umum untuk UPSERT massal:
- Bagaimana cara menggunakan RETURNING dengan ON CONFLICT di PostgreSQL?
Tanpa beban tulis bersamaan
Jika penulisan bersamaan (dari sesi yang berbeda) tidak memungkinkan, Anda tidak perlu mengunci baris dan dapat menyederhanakan:
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;