Masalah
Manual menjelaskan:
RETURNINGopsional klausa menyebabkanUPDATEuntuk 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 dariRETURNINGlist 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