Indeks unik yang difilter adalah ide yang brilian tetapi memiliki sedikit kerugian - tidak peduli apakah Anda menggunakan WHERE identity_column > <current value>
kondisi atau WHERE identity_column NOT IN (<list of ids for duplicate values here>)
.
Dengan pendekatan pertama, Anda masih dapat memasukkan data duplikat di masa depan, duplikat data yang ada (sekarang). Misalnya, jika Anda memiliki (bahkan hanya satu) baris sekarang CompanyName = 'Software Inc.'
, indeks tidak akan melarang penyisipan satu baris lagi dengan nama perusahaan yang sama. Itu hanya akan melarangnya jika Anda mencoba dua kali.
Dengan pendekatan kedua ada peningkatan, hal di atas tidak akan bekerja (yang baik.) Namun, Anda masih dapat memasukkan lebih banyak duplikat atau duplikat yang ada. Misalnya, jika Anda memiliki (dua atau lebih) baris dengan sekarang CompanyName = 'DoubleData Co.'
, indeks tidak akan melarang penyisipan satu baris lagi dengan nama perusahaan yang sama. Itu hanya akan melarangnya jika Anda mencoba dua kali.
(Pembaruan) Ini dapat diperbaiki jika untuk setiap nama duplikat, Anda tetap keluar dari daftar pengecualian satu id. Jika, seperti contoh di atas, ada 4 baris dengan duplikat CompanyName = DoubleData Co.
dan ID 4,6,8,9
, daftar pengecualian harus hanya memiliki 3 ID ini.
Dengan pendekatan kedua kelemahan lain adalah kondisi rumit (berapa rumit tergantung pada berapa banyak duplikat ada di tempat pertama), karena SQL-Server tampaknya tidak mendukung NOT IN
operator di WHERE
bagian indeks yang difilter. Lihat SQL-Fiddle . Alih-alih WHERE (CompanyID NOT IN (3,7,4,6,8,9))
, Anda harus memiliki sesuatu seperti WHERE (CompanyID <> 3 AND CompanyID <> 7 AND CompanyID <> 4 AND CompanyID <> 6 AND CompanyID <> 8 AND CompanyID <> 9)
saya tidak yakin apakah ada implikasi efisiensi dengan kondisi seperti itu, jika Anda memiliki ratusan nama rangkap.
Solusi lain (mirip dengan @Alex Kuznetsov) adalah menambahkan kolom lain, mengisinya dengan nomor peringkat dan menambahkan indeks unik termasuk kolom ini:
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) ;
Kemudian, memasukkan baris dengan nama duplikat akan gagal karena DEFAULT 1
properti dan indeks unik. Ini masih tidak 100% sangat mudah (sementara Alex adalah). Duplikat akan tetap masuk jika Rn
secara eksplisit diatur dalam INSERT
pernyataan atau jika Rn
nilainya diperbarui secara jahat.
SQL-Fiddle-2