PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Postgres UPDATE dengan ORDER BY, bagaimana melakukannya?

Sejauh yang saya tahu, tidak ada cara untuk mencapai ini secara langsung melalui UPDATE penyataan; satu-satunya cara untuk menjamin urutan penguncian adalah dengan memperoleh kunci secara eksplisit dengan SELECT ... ORDER BY ID FOR UPDATE , misalnya:

UPDATE Balances
SET Balance = 0
WHERE ID IN (
  SELECT ID FROM Balances
  WHERE ID IN (SELECT ID FROM some_function())
  ORDER BY ID
  FOR UPDATE
)

Ini memiliki kelemahan mengulang ID pencarian indeks pada Balances meja. Dalam contoh sederhana Anda, Anda dapat menghindari overhead ini dengan mengambil alamat baris fisik (diwakili oleh ctid kolom sistem ) selama kueri penguncian, dan menggunakannya untuk mendorong UPDATE :

UPDATE Balances
SET Balance = 0
WHERE ctid = ANY(ARRAY(
  SELECT ctid FROM Balances
  WHERE ID IN (SELECT ID FROM some_function())
  ORDER BY ID
  FOR UPDATE
))

(Hati-hati saat menggunakan ctid s, karena nilainya bersifat sementara. Kami aman di sini, karena kunci akan memblokir perubahan apa pun.)

Sayangnya, perencana hanya akan menggunakan ctid dalam serangkaian kasus yang sempit (Anda dapat mengetahui apakah itu berfungsi dengan mencari simpul "Pemindaian Tid" di EXPLAIN keluaran). Untuk menangani kueri yang lebih rumit dalam satu UPDATE pernyataan, mis. jika saldo baru Anda dikembalikan oleh some_function() di samping ID, Anda harus kembali ke pencarian berbasis ID:

UPDATE Balances
SET Balance = Locks.NewBalance
FROM (
  SELECT Balances.ID, some_function.NewBalance
  FROM Balances
  JOIN some_function() ON some_function.ID = Balances.ID
  ORDER BY Balances.ID
  FOR UPDATE
) Locks
WHERE Balances.ID = Locks.ID

Jika overhead kinerja menjadi masalah, Anda harus menggunakan kursor, yang akan terlihat seperti ini:

DO $$
DECLARE
  c CURSOR FOR
    SELECT Balances.ID, some_function.NewBalance
    FROM Balances
    JOIN some_function() ON some_function.ID = Balances.ID
    ORDER BY Balances.ID
    FOR UPDATE;
BEGIN
  FOR row IN c LOOP
    UPDATE Balances
    SET Balance = row.NewBalance
    WHERE CURRENT OF c;
  END LOOP;
END
$$


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Menghubungkan ke instance lokal PostgreSql dengan JDBC

  2. Tetapkan batas default untuk pg_trgm

  3. Pembuatan urutan berurutan

  4. Tidak dapat mengimpor .csv ke Cloud SQL dari konsol

  5. Bagaimana cara menghapus tanda kutip tunggal dari tabel di postgresql?