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

Xóa phụ huynh nếu nó không được tham chiếu bởi bất kỳ đứa trẻ nào khác

Trong PostgreSQL 9.1 trở lên bạn có thể thực hiện việc này chỉ với một câu lệnh sử dụng CTE sửa đổi dữ liệu . Điều này thường ít xảy ra lỗi hơn. Nó giảm thiểu khung thời gian giữa hai DELETE trong đó điều kiện cuộc đua có thể dẫn đến kết quả đáng ngạc nhiên với các hoạt động đồng thời:

WITH del_child AS (
    DELETE FROM child
    WHERE  child_id = 1
    RETURNING parent_id, child_id
    )
DELETE FROM parent p
USING  del_child x
WHERE  p.parent_id = x.parent_id
AND    NOT EXISTS (
   SELECT 1
   FROM   child c
   WHERE  c.parent_id = x.parent_id
   AND    c.child_id <> x.child_id   -- !
   );

SQL Fiddle.

Đứa trẻ bị xóa trong mọi trường hợp. Tôi trích dẫn sách hướng dẫn:

Các câu lệnh sửa đổi dữ liệu trong WITH được thực thi chính xác một lần và luôn hoàn thành , không phụ thuộc vào việc truy vấn chính có đọc tất cả (hoặc thực sự là bất kỳ) đầu ra của chúng hay không. Lưu ý rằng điều này khác với quy tắc cho SELECT trong WITH :như đã nêu trong phần trước, việc thực thi SELECT chỉ được thực hiện khi truy vấn chính và kết quả đầu ra của nó.

Cấp độ gốc chỉ bị xóa nếu nó không có khác trẻ em.
Lưu ý điều kiện cuối cùng. Trái ngược với những gì người ta có thể mong đợi, điều này là cần thiết, vì:

Các câu lệnh con trong WITH được thực thi đồng thời với mỗi otherand với truy vấn chính. Do đó, khi sử dụng các câu lệnh sửa đổi dữ liệu trong WITH , thứ tự mà các bản cập nhật được chỉ định thực sự xảy ra là không thể đoán trước. Tất cả các câu lệnh được thực thi bằng samesnapshot (xem Chương 13), vì vậy chúng không thể "nhìn thấy" các hiệu ứng của nhau trên các bảng đích.

Nhấn mạnh đậm của tôi.
Tôi đã sử dụng tên cột parent_id thay cho id không mô tả .

Loại bỏ tình trạng chủng tộc

Để loại bỏ các điều kiện chủng tộc có thể xảy ra, tôi đã đề cập ở trên hoàn toàn , khóa hàng mẹ đầu tiên . Tất nhiên, tất cả các hoạt động tương tự phải tuân theo cùng một quy trình để làm cho nó hoạt động.

WITH lock_parent AS (
   SELECT p.parent_id, c.child_id
   FROM   child  c
   JOIN   parent p ON p.parent_id = c.parent_id
   WHERE  c.child_id = 12              -- provide child_id here once
   FOR    NO KEY UPDATE                -- locks parent row.
   )
 , del_child AS (
   DELETE FROM child c
   USING  lock_parent l
   WHERE  c.child_id = l.child_id
   )
DELETE FROM parent p
USING  lock_parent l
WHERE  p.parent_id = l.parent_id
AND    NOT EXISTS (
   SELECT 1
   FROM   child c
   WHERE  c.parent_id = l.parent_id
   AND    c.child_id <> l.child_id   -- !
   );

Cách này chỉ một giao dịch tại một thời điểm có thể khóa cùng một cha mẹ. Vì vậy, không thể xảy ra trường hợp nhiều giao dịch xóa các con của cùng một phụ huynh, vẫn nhìn thấy các trẻ em khác và tha cho phụ huynh đó, trong khi tất cả các trẻ em đã biến mất sau đó. (Cập nhật trên các cột không phải khóa vẫn được phép với FOR NO KEY UPDATE .)

Nếu những trường hợp như vậy không bao giờ xảy ra hoặc bạn có thể sống chung với nó (hiếm khi) xảy ra - truy vấn đầu tiên sẽ rẻ hơn. Mặt khác, đây là đường dẫn an toàn.

FOR NO KEY UPDATE đã được giới thiệu với Postgres 9.4. Chi tiết trong sách hướng dẫn. Trong các phiên bản cũ hơn, hãy sử dụng khóa mạnh hơn FOR UPDATE thay vào đó.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách triển khai PostgreSQL trên DigitalOcean

  2. Có cái gì đó giống như một hàm zip () trong PostgreSQL kết hợp hai mảng không?

  3. Lỗi drop Rails + Postgres:cơ sở dữ liệu đang được người dùng khác truy cập

  4. Cấp đặc quyền cho một cơ sở dữ liệu cụ thể trong PostgreSQL

  5. Sự cố khi chèn bằng psycopg