SQL Server 2008 trở lên
Chỉ cần lọc một chỉ mục duy nhất:
CREATE UNIQUE NONCLUSTERED INDEX UQ_Party_SamAccountName
ON dbo.Party(SamAccountName)
WHERE SamAccountName IS NOT NULL;
Trong các phiên bản thấp hơn, Chế độ xem cụ thể vẫn không bắt buộc
Đối với SQL Server 2005 trở về trước, bạn có thể làm điều đó mà không cần xem. Tôi vừa thêm một ràng buộc duy nhất như bạn đang yêu cầu một trong các bảng của mình. Cho rằng tôi muốn tính duy nhất trong cột SamAccountName
, nhưng tôi muốn cho phép nhiều NULL, tôi đã sử dụng một cột được vật chất hóa thay vì một khung nhìn cụ thể hóa:
ALTER TABLE dbo.Party ADD SamAccountNameUnique
AS (Coalesce(SamAccountName, Convert(varchar(11), PartyID)))
ALTER TABLE dbo.Party ADD CONSTRAINT UQ_Party_SamAccountName
UNIQUE (SamAccountNameUnique)
Bạn chỉ cần đặt một cái gì đó vào cột được tính sẽ được đảm bảo duy nhất trên toàn bộ bảng khi cột duy nhất mong muốn thực tế là NULL. Trong trường hợp này, PartyID
là một cột danh tính và là số sẽ không bao giờ khớp với bất kỳ SamAccountName
, vì vậy nó hoạt động với tôi. Bạn có thể thử phương pháp của riêng mình, hãy chắc chắn rằng bạn hiểu miền của dữ liệu của mình để không có khả năng giao nhau với dữ liệu thực. Điều đó có thể đơn giản như việc chuẩn bị một nhân vật khác biệt như thế này:
Coalesce('n' + SamAccountName, 'p' + Convert(varchar(11), PartyID))
Ngay cả khi PartyID
trở thành phi số một ngày nào đó và có thể trùng với một SamAccountName
, bây giờ nó không thành vấn đề.
Lưu ý rằng sự hiện diện của một chỉ mục bao gồm cột được tính toán khiến cho mỗi kết quả biểu thức được lưu vào đĩa với dữ liệu khác trong bảng mà DOES chiếm thêm không gian đĩa.
Lưu ý rằng nếu bạn không muốn có một chỉ mục, bạn vẫn có thể lưu CPU bằng cách làm cho biểu thức được định sẵn vào đĩa bằng cách thêm từ khóa PERSISTED
vào cuối định nghĩa biểu thức cột.
Trong SQL Server 2008 trở lên, chắc chắn sử dụng giải pháp được lọc thay thế nếu bạn có thể!
Tranh cãi
Xin lưu ý rằng một số chuyên gia cơ sở dữ liệu sẽ xem đây là trường hợp "thay thế NULL", điều này chắc chắn có vấn đề (chủ yếu là do các vấn đề xung quanh cố gắng xác định khi nào đó là giá trị thực hoặc giá trị thay thế cho dữ liệu bị thiếu ; cũng có thể có vấn đề với số lượng giá trị thay thế không phải NULL nhân lên như điên).
Tuy nhiên, tôi tin rằng trường hợp này là khác nhau. Cột được tính mà tôi thêm sẽ không bao giờ được sử dụng để xác định bất cứ điều gì. Bản thân nó không có ý nghĩa gì và mã hóa không có thông tin nào chưa được tìm thấy riêng trong các cột khác, được xác định đúng. Nó không bao giờ nên được lựa chọn hoặc sử dụng.
Vì vậy, câu chuyện của tôi là đây không phải là một NULL thay thế, và tôi đang gắn bó với nó! Vì chúng tôi thực sự không muốn giá trị không phải NULL cho bất kỳ mục đích nào ngoài mục đích lừa UNIQUE
chỉ mục bỏ qua NULL, trường hợp sử dụng của chúng tôi không có vấn đề nào phát sinh với việc tạo NULL thay thế bình thường.
Tất cả những gì đã nói, tôi không có vấn đề gì với việc sử dụng chế độ xem được lập chỉ mục thay vào đó, nhưng nó mang lại một số vấn đề với nó, chẳng hạn như yêu cầu sử dụng SCHEMABINDING
. Vui khi thêm một cột mới vào bảng cơ sở của bạn (tối thiểu bạn sẽ phải bỏ chỉ mục, sau đó thả chế độ xem hoặc thay đổi chế độ xem để không bị ràng buộc lược đồ). Xem danh sách đầy đủ (dài) các yêu cầu để tạo chế độ xem được lập chỉ mục trong SQL Server (2005) (cũng là các phiên bản mới hơn), (2000) .
Cập nhật
Nếu cột của bạn là số, có thể có thách thức đảm bảo rằng ràng buộc duy nhất sử dụng Coalesce
không dẫn đến va chạm. Trong trường hợp đó, có một số tùy chọn. Người ta có thể sử dụng số âm, chỉ đặt "NULL thay thế" trong phạm vi âm và "giá trị thực" chỉ trong phạm vi dương. Thay phiên, mô hình sau đây có thể được sử dụng. Trong bảng Issue
(nơi IssueID
là PRIMARY KEY
), có thể có hoặc không có một TicketID
, nhưng nếu có một, nó phải là duy nhất.
ALTER TABLE dbo.Issue ADD TicketUnique
AS (CASE WHEN TicketID IS NULL THEN IssueID END);
ALTER TABLE dbo.Issue ADD CONSTRAINT UQ_Issue_Ticket_AllowNull
UNIQUE (TicketID, TicketUnique);
Nếu IssueID 1 có vé 123, UNIQUE
ràng buộc sẽ là các giá trị (123, NULL). Nếu IssueID 2 không có vé, nó sẽ được bật (NULL, 2). Một số suy nghĩ sẽ cho thấy ràng buộc này không thể được nhân đôi cho bất kỳ hàng nào trong bảng và vẫn cho phép nhiều NULL.