Giống như @ lad2025 đã nhận xét , status
thực sự phải là boolean
. Rẻ hơn, sạch hơn.
Dù bằng cách nào, bạn có thể áp đặt quy tắc của mình với chỉ mục duy nhất một phần :
Để cho phép không hoặc một hàng có status = 'Active'
trong toàn bộ bảng :
CREATE UNIQUE INDEX tbl_active_uni ON tbl (status)
WHERE status = 'Active';
Để cho phép không hoặc một hàng có status = 'Active'
per userid
, tạo userid
cột được lập chỉ mục:
CREATE UNIQUE INDEX tbl_userid_active_uni ON tbl (userid)
WHERE status = 'Active';
Lưu ý rằng userid IS NULL
sẽ không kích hoạt các vi phạm duy nhất, bởi vì hai giá trị NULL không bao giờ được coi là bằng nhau. userid
phải là đặt NOT NULL
trong trường hợp này.
Tại sao phải lập chỉ mục chứ không phải ràng buộc?
Giải quyết câu hỏi trong nhận xét
:Đây là chỉ mục, không phải là CONSTRAINT
.
Chỉ mục cho trường hợp đầu tiên là tiny , giữ một hoặc không có hàng.
Chỉ mục cho trường hợp thứ hai giữ một hàng trên mỗi userid
hiện có , nhưng đó là cách rẻ nhất và nhanh nhất , ngoài việc sạch sẽ và an toàn. Bạn sẽ cần một chỉ mục để kiểm tra các hàng khác trong mọi trường hợp để thực hiện việc này nhanh chóng.
Bạn không thể có CHECK
kiểm tra ràng buộc trên các hàng khác - ít nhất là không theo kiểu sạch sẽ, đáng tin cậy. Có những cách tôi chắc chắn không khuyên dùng cho trường hợp này:
- Ràng buộc kiểm tra kích hoạt và kiểm tra
- Làm cách nào để tránh phụ thuộc theo chu kỳ (tham chiếu vòng tròn) giữa 3 bảng?
- Tắt tất cả các ràng buộc và kiểm tra bảng trong khi khôi phục kết xuất
Nếu bạn sử dụng UNIQUE
ràng buộc về (userid, status)
(cũng được triển khai với một chỉ mục duy nhất trong nền!), bạn không thể biến nó thành một phần và tất cả các kết hợp được thực thi để trở thành duy nhất. Bạn có thể vẫn sử dụng điều này nếu bạn làm việc với trạng thái status IS NULL
cho mọi trường hợp ngoại trừ 'Active'
trường hợp. Nhưng điều đó thực sự sẽ áp đặt một chỉ số lớn hơn nhiều bao gồm tất cả hàng.