Postgresql: Ràng buộc duy nhất có điều kiện


116

Tôi muốn thêm một ràng buộc thực thi tính duy nhất trên một cột chỉ trong một phần của bảng.

ALTER TABLE stop ADD CONSTRAINT myc UNIQUE (col_a) WHERE (col_b is null);

Phần WHEREtrên là mơ tưởng.

Bất kỳ cách nào để làm điều này? Hay tôi nên quay lại bảng vẽ quan hệ?


2
Thường được thực hiện. Xem "chỉ mục duy nhất một phần"
Craig Ringer

11
@yvesonline không, đó là một ràng buộc duy nhất thường xuyên. Người đăng muốn có một hạn chế duy nhất một phần .
Craig Ringer

Câu trả lời:


186

PostgreSQL không xác định UNIQUEràng buộc một phần (tức là có điều kiện) - tuy nhiên, bạn có thể tạo một chỉ mục duy nhất một phần . PostgreSQL sử dụng các chỉ mục duy nhất để triển khai các ràng buộc duy nhất, vì vậy hiệu quả là như nhau, bạn sẽ không thấy ràng buộc được liệt kê trong information_schema.

CREATE UNIQUE INDEX stop_myc ON stop (col_a) WHERE (col_b is NOT null);

Xem chỉ mục từng phần .


24
Siêu! Unintuitive rằng "hạn chế" không hiển thị là một hạn chế, nhưng dù sao cung cấp cho các lỗi mong muốnERROR: duplicate key value violates unique constraint "stop_myc"
EoghanM

7
Cần lưu ý rằng điều này sẽ không cho phép tạo tham chiếu FKs trường duy nhất một phần.
ffflabs

11
Cũng cần lưu ý rằng không thể trì hoãn hiệu ứng chỉ mục này. Nếu bạn cần thực hiện cập nhật hàng loạt, điều này có thể gây ra sự cố vì tính duy nhất được kiểm tra sau mỗi hàng, không phải sau câu lệnh như đối với ràng buộc hoặc sau giao dịch giống như đối với ràng buộc có thể hoãn lại.
sage88

37

người ta đã nói rằng PG không xác định ràng buộc UNIQUE một phần (có điều kiện). Ngoài ra, tài liệu nói rằng cách ưa thích để thêm một ràng buộc duy nhất vào bảng là ADD CONSTRAINT Chỉ mục duy nhất

Cách ưa thích để thêm một ràng buộc duy nhất vào bảng là ALTER TABLE ... ADD CONSTRAINT. Việc sử dụng các chỉ mục để thực thi các ràng buộc duy nhất có thể được coi là một chi tiết triển khai không nên được truy cập trực tiếp. Tuy nhiên, cần lưu ý rằng không cần phải tạo chỉ mục theo cách thủ công trên các cột duy nhất; làm như vậy sẽ chỉ nhân bản chỉ mục được tạo tự động.

Có một cách để triển khai nó bằng cách sử dụng Ràng buộc loại trừ , (cảm ơn @dukelion về giải pháp này)

Trong trường hợp của bạn, nó sẽ giống như

ALTER TABLE stop ADD CONSTRAINT myc EXCLUDE (col_a WITH =) WHERE (col_b IS null);

trên cách tiếp cận đó, bạn không sử dụng "using" để xác định phương thức chỉ mục, do đó có thể cực kỳ chậm hoặc postgres tạo một chỉ mục mặc định trên đó? Phương pháp đó là lựa chọn kinh điển, nhưng không bao giờ là lựa chọn tốt hơn! Tôi nghĩ bạn sẽ cần một mệnh đề "using" với chỉ mục để làm cho lựa chọn đó tốt hơn.
Natan Medeiros

10
Mặc dù chậm hơn, nhưng lợi thế của giải pháp loại trừ là nó có thể được hoãn lại (và theo mặc định là định nghĩa cho đến khi kết thúc câu lệnh). Ngược lại, giải pháp chỉ mục duy nhất được chấp nhận không thể được hoãn lại (và được kiểm tra sau mỗi lần thay đổi hàng). Vì vậy, cập nhật hàng loạt thường không thể thực hiện được vì các bước trong quá trình cập nhật sẽ vi phạm giới hạn duy nhất, ngay cả khi nó sẽ không bị vi phạm ở cuối câu lệnh cập nhật nguyên tử.
sage88

1
Ghi chú này đã được xóa khỏi tài liệu vào tháng 8 năm 2015
Raniz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.