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

Trả về giá trị cột trước UPDATE chỉ bằng SQL

Vấn đề

Sách hướng dẫn giải thích:

RETURNING tùy chọn mệnh đề nguyên nhân UPDATE để tính toán và (các) giá trị trả về dựa trên mỗi hàng được cập nhật thực sự. Bất kỳ biểu thức nào sử dụng các cột của bảng và / hoặc các cột của các bảng khác được đề cập trong FROM , có thể được tính toán. Các giá trị mới (sau cập nhật) của các cột trong bảng được sử dụng . Cú pháp của RETURNING danh sách giống với danh sách đầu ra của SELECT .

Tôi nhấn mạnh đậm. Không có cách nào để truy cập hàng cũ trong RETURNING mệnh đề. Bạn có thể khắc phục hạn chế này bằng trình kích hoạt hoặc SELECT riêng biệt trước đây UPDATE được bao bọc trong một giao dịch hoặc được bao bọc trong một CTE như đã được nhận xét.

Tuy nhiên, những gì bạn đang cố gắng đạt được hoạt động hoàn toàn tốt nếu bạn tham gia vào một phiên bản khác của bảng trong FROM mệnh đề:

Giải pháp không ghi đồng thời

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;

Lợi nhuận:

 old_id | old_name | tbl_id |  name
--------+----------+--------+---------
  3     | Old Guy  | 23     | New Guy

(Các) cột được sử dụng để tự tham gia phải UNIQUE NOT NULL . Trong ví dụ đơn giản, WHERE điều kiện nằm trên cùng một cột tbl_id , nhưng đó chỉ là sự trùng hợp ngẫu nhiên. Hoạt động cho bất kỳ điều kiện.

Tôi đã thử nghiệm điều này với các phiên bản PostgreSQL từ 8.4 đến 13.

Nó khác với INSERT :

  • CHÈN VÀO ... TỪ CHỌN ... QUAY LẠI ánh xạ id

Các giải pháp có tải ghi đồng thời

Có nhiều cách khác nhau để tránh các điều kiện chạy đua với các thao tác ghi đồng thời trên các hàng giống nhau. (Lưu ý rằng các thao tác ghi đồng thời trên các hàng không liên quan hoàn toàn không có vấn đề gì.) Phương pháp đơn giản, chậm và chắc chắn (nhưng đắt tiền) là chạy giao dịch với SERIALIZABLE mức độ cô lập:

BEGIN ISOLATION LEVEL SERIALIZABLE;
UPDATE ... ;
COMMIT;

Nhưng đó có lẽ là quá mức cần thiết. Và bạn cần chuẩn bị để lặp lại thao tác trong trường hợp tuần tự hóa bị lỗi.

Đơn giản hơn và nhanh hơn (và cũng đáng tin cậy với tải ghi đồng thời) là một khóa rõ ràng trên một hàng sẽ được cập nhật:

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;

Lưu ý cách WHERE điều kiện được chuyển đến truy vấn con (một lần nữa, có thể là bất kỳ điều gì ), và chỉ tự tham gia (trên UNIQUE NOT NULL (các) cột) vẫn còn trong truy vấn bên ngoài. Điều này đảm bảo rằng chỉ các hàng bị khóa bởi SELECT bên trong được xử lý. WHERE các điều kiện có thể giải quyết thành một tập hợp hàng khác ngay sau đó.

Xem:

  • CẬP NHẬT nguyên tử .. CHỌN trong Postgres

db <> fiddle here
Sqlfiddle cũ



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Psycopg2 sử dụng hết bộ nhớ trên truy vấn chọn lọc lớn

  2. Điều cần kiểm tra xem Khả năng sử dụng bộ nhớ PostgreSQL có cao không

  3. Điều chỉnh PostgreSQL:Những điều quan trọng để thúc đẩy hiệu suất

  4. Làm cách nào để thay đổi mã hóa cơ sở dữ liệu cho cơ sở dữ liệu PostgreSQL bằng sql hoặc phpPgAdmin?

  5. Thực hiện thay đổi cấu trúc liên kết sao chép cho PostgreSQL