Masalah
Manual menjelaskan:
RETURNING
opsional klausa menyebabkanUPDATE
untuk menghitung dan mengembalikan nilai berdasarkan setiap baris yang benar-benar diperbarui. Ekspresi apa pun yang menggunakan kolom tabel, dan/atau kolom tabel lain yang disebutkan dalamFROM
, dapat dihitung. Nilai baru (pasca-pembaruan) dari kolom tabel digunakan . Sintaks dariRETURNING
list identik dengan daftar keluaranSELECT
.
Penekanan saya yang berani. Tidak ada cara untuk mengakses baris lama dalam RETURNING
ayat. Anda dapat mengatasi pembatasan ini dengan pemicu atau SELECT
separate yang terpisah sebelum UPDATE
dibungkus dalam transaksi atau dibungkus dengan CTE seperti yang dikomentari.
Namun, apa yang Anda coba capai berfungsi dengan baik jika Anda bergabung ke instance lain dari tabel di FROM
klausa:
Solusi tanpa penulisan bersamaan
UPDATE tbl x
SET tbl_id = 23
, name = 'New Guy'
FROM tbl y -- using the FROM clause
WHERE x.tbl_id = y.tbl_id -- must be UNIQUE NOT NULL
AND x.tbl_id = 3
RETURNING y.tbl_id AS old_id, y.name AS old_name
, x.tbl_id , x.name;
Pengembalian:
old_id | old_name | tbl_id | name
--------+----------+--------+---------
3 | Old Guy | 23 | New Guy
Kolom yang digunakan untuk bergabung sendiri harus UNIQUE NOT NULL
. Dalam contoh sederhana, WHERE
kondisi pada kolom yang sama tbl_id
, tapi itu hanya kebetulan. Bekerja untuk apa saja kondisi.
Saya menguji ini dengan versi PostgreSQL dari 8.4 hingga 13.
Ini berbeda untuk INSERT
:
- MASUKKAN KE ... DARI PILIH ... MENGEMBALIKAN pemetaan id
Solusi dengan beban tulis bersamaan
Ada berbagai cara untuk menghindari kondisi balapan dengan operasi penulisan bersamaan pada baris yang sama. (Perhatikan bahwa operasi penulisan bersamaan pada baris yang tidak terkait sama sekali tidak masalah.) Metode sederhana, lambat dan pasti (tapi mahal) adalah menjalankan transaksi dengan SERIALIZABLE
tingkat isolasi:
BEGIN ISOLATION LEVEL SERIALIZABLE;
UPDATE ... ;
COMMIT;
Tapi itu mungkin berlebihan. Dan Anda harus bersiap untuk mengulangi operasi jika terjadi kegagalan serialisasi.
Lebih sederhana dan lebih cepat (dan sama andalnya dengan beban tulis bersamaan) adalah kunci eksplisit pada satu baris yang akan diperbarui:
UPDATE tbl x
SET tbl_id = 24
, name = 'New Gal'
FROM (SELECT tbl_id, name FROM tbl WHERE tbl_id = 4 FOR UPDATE) y
WHERE x.tbl_id = y.tbl_id
RETURNING y.tbl_id AS old_id, y.name AS old_name
, x.tbl_id , x.name;
Perhatikan bagaimana WHERE
kondisi dipindahkan ke subquery (sekali lagi, bisa apa saja ), dan hanya self-join (pada UNIQUE NOT NULL
column(s)) tetap berada di kueri luar. Ini menjamin bahwa hanya baris yang dikunci oleh SELECT
inner bagian dalam diproses. WHERE
kondisi mungkin berubah menjadi kumpulan baris yang berbeda beberapa saat kemudian.
Lihat:
- PEMBARUAN Atom .. PILIH di Postgres
db<>main biola di sini
sqlfiddle lama