PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Postgres UPDATE với ORDER BY, làm thế nào để làm điều đó?

Theo như tôi biết, không có cách nào để thực hiện điều này trực tiếp thông qua UPDATE bản tường trình; cách duy nhất để đảm bảo thứ tự khóa là có được khóa một cách rõ ràng bằng SELECT ... ORDER BY ID FOR UPDATE , ví dụ:

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
)

Điều này có mặt trái của việc lặp lại ID tra cứu chỉ mục trên Balances bàn. Trong ví dụ đơn giản của bạn, bạn có thể tránh chi phí này bằng cách tìm nạp địa chỉ hàng vật lý (được đại diện bởi ctid cột hệ thống ) trong khi truy vấn khóa và sử dụng điều đó để thúc đẩy 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
))

(Hãy cẩn thận khi sử dụng ctid s, vì các giá trị là tạm thời. Chúng tôi ở đây an toàn, vì ổ khóa sẽ chặn mọi thay đổi.)

Thật không may, người lập kế hoạch sẽ chỉ sử dụng ctid trong một số trường hợp hẹp (bạn có thể biết nó có hoạt động hay không bằng cách tìm nút "Quét Tid" trong EXPLAIN đầu ra). Để xử lý các truy vấn phức tạp hơn trong một UPDATE duy nhất tuyên bố, ví dụ:nếu số dư mới của bạn được trả lại bởi some_function() cùng với ID, bạn sẽ cần quay lại tra cứu dựa trên 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

Nếu chi phí hiệu suất là một vấn đề, bạn cần phải sử dụng con trỏ, con trỏ sẽ trông giống như sau:

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. Chạy truy vấn với LIMIT / OFFSET và cũng nhận được tổng số hàng

  2. TimescaleDB:chọn hàng cuối cùng một cách hiệu quả

  3. Cách sạch sẽ để sử dụng các chức năng cửa sổ postgresql trong django ORM?

  4. Postgres:Ràng buộc chỉ bằng kiểm tra CHÈN

  5. Tải hàng loạt vào PostgreSQL từ một máy khách từ xa