Фільтрований унікальний індекс - це геніальна ідея, але він має незначний недолік - незалежно від того, використовуєте ви WHERE identity_column > <current value>умову чи WHERE identity_column NOT IN (<list of ids for duplicate values here>).
При першому підході ви все одно зможете вставити дублікати даних у майбутньому, дублікати існуючих (зараз) даних. Наприклад, якщо у вас зараз (навіть лише один) рядок CompanyName = 'Software Inc.', індекс не забороняє вставляти ще один рядок з такою ж назвою компанії. Це заборонить, лише якщо спробувати двічі.
З другим підходом відбувається поліпшення, вищезгадане не вийде (що добре.) Однак ви все одно зможете вставити більше дублікатів або існуючих дублікатів. Наприклад, якщо у вас зараз (два або більше) рядків CompanyName = 'DoubleData Co.', індекс не забороняє вставляти ще один рядок з такою ж назвою компанії. Це заборонить, лише якщо спробувати двічі.
(Оновлення) Це можна виправити, якщо для кожного дублюючого імені ви зберігаєте зі списку виключень один ідентифікатор. Якщо, як у наведеному вище прикладі, є 4 рядки з дублікатами CompanyName = DoubleData Co.та ідентифікаторами 4,6,8,9, у списку виключень має бути лише 3 з цих ідентифікаторів.
При другому підході ще одним недоліком є громіздка умова (наскільки громіздка залежить від того, скільки дублікатів є в першу чергу), оскільки SQL-Server, здається, не підтримує NOT INоператора в WHEREчастині відфільтрованих індексів. Див. SQL-Fiddle . Замість цього WHERE (CompanyID NOT IN (3,7,4,6,8,9))вам доведеться мати щось на зразок WHERE (CompanyID <> 3 AND CompanyID <> 7 AND CompanyID <> 4 AND CompanyID <> 6 AND CompanyID <> 8 AND CompanyID <> 9)я не впевнений, чи є наслідки для ефективності з такою умовою, якщо у вас є сотні дублюючих імен.
Інше рішення (подібне до @Alex Kuznetsov) - додати ще один стовпець, заповнити його ранговими номерами та додати унікальний індекс, що включає цей стовпець:
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) ;
Тоді вставлення рядка з повторюваним іменем не вдасться через DEFAULT 1властивість та унікальний індекс. Це все ще не на 100% бездоганний (у той час як Алекс). Дублікати все одно проскакують, якщо Rnявно встановлено у INSERTвиписці або якщо Rnзначення зловмисно оновлюються.
SQL-Fiddle-2