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

Xác thực tính duy nhất trong cơ sở dữ liệu khi xác thực có một điều kiện trên bảng khác

Thật không may, không có giải pháp nào đơn giản và sạch sẽ như đối với câu hỏi trước của bạn .

Điều này sẽ thực hiện công việc:

  • Thêm cờ dự phòng is_published đến Child bảng

    ALTER TABLE child ADD column is_published boolean NOT NULL;
    

    Đặt nó thành DEFAULT FALSE hoặc bất kỳ thứ gì bạn thường có trong các cột chính khi chèn.
    Nó cần phải là NOT NULL để tránh sơ hở với NULL giá trị và MATCH SIMPLE mặc định hành vi trong khóa ngoại:
    Ràng buộc khóa ngoại hai cột chỉ khi cột thứ ba KHÔNG ĐẦY ĐỦ

  • Thêm một ràng buộc duy nhất (dường như vô nghĩa, nhưng) trên parent(parent_id, is_published)

    ALTER TABLE parent ADD CONSTRAINT parent_fk_uni
    UNIQUE (parent_id, is_published);
    

    Kể từ parent_id là khóa chính, cách kết hợp sẽ là duy nhất. Nhưng điều đó là bắt buộc đối với ràng buộc fk sau đây.

  • Thay vì tham chiếu đến parent(parent_id) đơn giản với ràng buộc khóa ngoại , tạo khóa ngoại nhiều cột trên (parent_id, is_published) với ON UPDATE CASCADE .
    Bằng cách này, trạng thái của child.is_published được duy trì và thực thi bởi hệ thống tự động và đáng tin cậy hơn những gì bạn có thể triển khai với các trình kích hoạt tùy chỉnh:

    ALTER TABLE child
    ADD CONSTRAINT child_special_fkey FOREIGN KEY (parent_id, is_published)
    REFERENCES parent (parent_id, is_published) ON UPDATE CASCADE;
    
  • Sau đó, thêm một một phần chỉ mục UNIQUE như trong câu trả lời trước của bạn.

    CREATE UNIQUE INDEX child_txt_is_published_idx ON child (text)
    WHERE is_published;
    

Tất nhiên, khi chèn các hàng trong child bảng bạn buộc phải sử dụng trạng thái hiện tại của parent.is_published bây giờ. Nhưng đó là vấn đề:thực thi tính toàn vẹn của tham chiếu.

Lược đồ hoàn chỉnh

Hoặc, thay vì điều chỉnh một lược đồ hiện có, đây là bố cục hoàn chỉnh:

CREATE TABLE parent(
    parent_id serial PRIMARY KEY
  , is_published bool NOT NULL DEFAULT FALSE
--, more columns ...
  , UNIQUE (parent_id, is_published)   -- required for fk
);

CREATE TABLE child (
    child_id serial PRIMARY KEY
  , parent_id integer NOT NULL
  , is_published bool NOT NULL DEFAULT FALSE
  , txt text
  , FOREIGN KEY (parent_id, is_published)
      REFERENCES parent (parent_id, is_published) ON UPDATE CASCADE
);

CREATE UNIQUE INDEX child_txt_is_published_idx ON child (text)
WHERE is_published;



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Postgres type {field type} chỉ là một shell

  2. Tạo một bảng gồm hai loại trong PostgreSQL

  3. Ràng buộc loại trừ `EXCLUDE USING gist (c WITH &&) 'nghĩa là gì?

  4. Lỗi cơ sở dữ liệu Postgres Tiêu đề trang không hợp lệ

  5. Tại sao hàm PostgreSQL json_agg () không trả về một mảng trống?