Chỉ số duy nhất được lọc là một ý tưởng tuyệt vời nhưng nó có một nhược điểm nhỏ - bất kể bạn sử dụng WHERE identity_column > <current value>
điều kiện hay WHERE identity_column NOT IN (<list of ids for duplicate values here>)
.
Với cách tiếp cận đầu tiên, bạn vẫn có thể chèn dữ liệu trùng lặp trong tương lai, trùng lặp dữ liệu hiện tại (hiện tại). Ví dụ: nếu bây giờ bạn có (thậm chí chỉ một) hàng CompanyName = 'Software Inc.'
, chỉ mục sẽ không cấm chèn thêm một hàng có cùng tên công ty. Nó sẽ chỉ cấm nó nếu bạn thử hai lần.
Với cách tiếp cận thứ hai có một cải tiến, cách trên sẽ không hoạt động (điều này tốt.) Tuy nhiên, bạn vẫn có thể chèn thêm các bản sao hoặc các bản sao hiện có. Ví dụ: nếu bây giờ bạn có (hai hoặc nhiều) hàng CompanyName = 'DoubleData Co.'
, chỉ mục sẽ không cấm chèn thêm một hàng có cùng tên công ty. Nó sẽ chỉ cấm nó nếu bạn thử hai lần.
(Cập nhật) Điều này có thể được sửa nếu với mỗi tên trùng lặp, bạn tránh xa danh sách loại trừ một id. Nếu, giống như ví dụ trên, có 4 hàng có trùng lặp CompanyName = DoubleData Co.
và ID 4,6,8,9
, danh sách loại trừ chỉ nên có 3 trong số các ID này.
Với cách tiếp cận thứ hai, một nhược điểm khác là điều kiện cồng kềnh (mức độ cồng kềnh phụ thuộc vào số lượng trùng lặp ở vị trí đầu tiên), vì SQL-Server dường như không hỗ trợ NOT IN
toán tử trong WHERE
phần chỉ mục được lọc. Xem SQL-Fiddle . Thay vì WHERE (CompanyID NOT IN (3,7,4,6,8,9))
, bạn sẽ phải có một cái gì đó giống như WHERE (CompanyID <> 3 AND CompanyID <> 7 AND CompanyID <> 4 AND CompanyID <> 6 AND CompanyID <> 8 AND CompanyID <> 9)
tôi không chắc có liên quan đến hiệu quả với điều kiện như vậy không, nếu bạn có hàng trăm tên trùng lặp.
Một giải pháp khác (tương tự như @Alex Kuznetsov) là thêm một cột khác, điền vào đó một số thứ hạng và thêm một chỉ mục duy nhất bao gồm cột này:
ALTER TABLE Company
ADD Rn TINYINT DEFAULT 1;
UPDATE x
SET Rn = Rnk
FROM
( SELECT
CompanyID,
Rn,
Rnk = ROW_NUMBER() OVER (PARTITION BY CompanyName
ORDER BY CompanyID)
FROM Company
) x ;
CREATE UNIQUE INDEX CompanyName_UQ
ON Company (CompanyName, Rn) ;
Sau đó, chèn một hàng với tên trùng lặp sẽ thất bại vì thuộc DEFAULT 1
tính và chỉ mục duy nhất. Điều này vẫn không thể đánh lừa 100% (trong khi Alex là). Các bản sao vẫn sẽ trượt vào nếu Rn
được đặt rõ ràng trong INSERT
câu lệnh hoặc nếu các Rn
giá trị được cập nhật độc hại.
SQL-Fiddle-2