Ngoài những gì @Craig cung cấp (và sửa một số lỗi):
Hiệu quả Postgres 9.4 , UNIQUE
, PRIMARY KEY
và EXCLUDE
hạn chế được kiểm tra ngay lập tức sau khi mỗi hàng khi được xác định NOT DEFERRABLE
. Điều này khác với các loại NOT DEFERRABLE
ràng buộc khác (hiện tại chỉ REFERENCES
(khóa ngoại)) được kiểm tra sau mỗi câu lệnh . Chúng tôi đã giải quyết tất cả những điều này theo câu hỏi liên quan này trên SO:
Sẽ không đủ để một ràng buộc UNIQUE
(hoặc PRIMARY KEY
hoặc EXCLUDE
) DEFERRABLE
làm cho mã được trình bày của bạn với nhiều câu lệnh hoạt động.
Và bạn không thể sử dụng ALTER TABLE ... ALTER CONSTRAINT
cho mục đích này. Mỗi tài liệu:
ALTER CONSTRAINT
Biểu mẫu này thay đổi các thuộc tính của một ràng buộc đã được tạo trước đó. Hiện tại chỉ có các ràng buộc khóa ngoại có thể được thay đổi .
Nhấn mạnh đậm của tôi. Sử dụng thay thế:
ALTER TABLE t
DROP CONSTRAINT category_name_key
, ADD CONSTRAINT category_name_key UNIQUE(name) DEFERRABLE;
Thả và thêm các ràng buộc trở lại trong một câu lệnh để không có cửa sổ thời gian cho bất kỳ ai lẻn vào các hàng vi phạm. Đối với các bảng lớn, sẽ rất hấp dẫn khi bảo tồn chỉ mục duy nhất tiềm ẩn bằng cách nào đó, bởi vì rất tốn kém để xóa và tạo lại nó. Than ôi, điều đó dường như là không thể với các công cụ tiêu chuẩn (nếu bạn có giải pháp cho điều đó, xin vui lòng cho chúng tôi biết!):
Đối với một tuyên bố duy nhất làm cho ràng buộc có thể được bảo vệ là đủ:
UPDATE category c
SET name = c_old.name
FROM category c_old
WHERE c.id IN (1,2)
AND c_old.id IN (1,2)
AND c.id <> c_old.id;
Một truy vấn với CTEs cũng là một đơn tuyên bố:
WITH x AS (
UPDATE category SET name = 'phones' WHERE id = 1
)
UPDATE category SET name = 'tablets' WHERE id = 2;
Tuy nhiên , đối với mã của bạn có nhiều câu lệnh, bạn (ngoài ra) cần thực sự trì hoãn ràng buộc - hoặc xác định nó là INITIALLY DEFERRED
Either thường đắt hơn so với ở trên. Nhưng nó có thể không dễ dàng khả thi để đóng gói mọi thứ vào một tuyên bố.
BEGIN;
SET CONSTRAINTS category_name_key DEFERRED;
UPDATE category SET name = 'phones' WHERE id = 1;
UPDATE category SET name = 'tablets' WHERE id = 2;
COMMIT;
Mặc dù vậy, hãy chú ý đến một giới hạn liên quan đến các FOREIGN KEY
ràng buộc. Mỗi tài liệu:
Các cột được tham chiếu phải là các cột của ràng buộc khóa chính hoặc duy nhất không thể bảo vệ trong bảng được tham chiếu.
Vì vậy, bạn không thể có cả hai cùng một lúc.