Saya ingin memiliki batasan unik pada kolom yang akan saya isi dengan GUID. Namun, data saya mengandung nilai nol untuk kolom ini. Bagaimana cara membuat batasan yang memungkinkan beberapa nilai null?
Berikut ini contoh skenario . Pertimbangkan skema ini:
CREATE TABLE People (
Id INT CONSTRAINT PK_MyTable PRIMARY KEY IDENTITY,
Name NVARCHAR(250) NOT NULL,
LibraryCardId UNIQUEIDENTIFIER NULL,
CONSTRAINT UQ_People_LibraryCardId UNIQUE (LibraryCardId)
)
Kemudian lihat kode ini untuk mengetahui apa yang ingin saya capai:
-- This works fine:
INSERT INTO People (Name, LibraryCardId)
VALUES ('John Doe', 'AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA');
-- This also works fine, obviously:
INSERT INTO People (Name, LibraryCardId)
VALUES ('Marie Doe', 'BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB');
-- This would *correctly* fail:
--INSERT INTO People (Name, LibraryCardId)
--VALUES ('John Doe the Second', 'AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA');
-- This works fine this one first time:
INSERT INTO People (Name, LibraryCardId)
VALUES ('Richard Roe', NULL);
-- THE PROBLEM: This fails even though I'd like to be able to do this:
INSERT INTO People (Name, LibraryCardId)
VALUES ('Marcus Roe', NULL);
Pernyataan terakhir gagal dengan pesan:
Pelanggaran batasan unik UNIQUE 'UQ_People_LibraryCardId'. Tidak dapat memasukkan kunci duplikat di objek 'dbo.People'.
Bagaimana saya bisa mengubah skema dan / atau batasan keunikan saya sehingga memungkinkan beberapa NULL
nilai, sambil tetap memeriksa keunikan pada data aktual?
sql-server
tsql
Stuart
sumber
sumber
null
itu bukan nilai tetapi tidak adanya nilai. Per standar SQL,null
tidak dianggap sama dengannull
. Jadi mengapa multiplenull
harus menjadi pelanggaran keunikan?Jawaban:
SQL Server 2008 +
Anda dapat membuat indeks unik yang menerima beberapa NULL dengan
WHERE
klausa. Lihat jawabannya di bawah .Sebelum ke SQL Server 2008
Anda tidak dapat membuat batasan UNIK dan mengizinkan NULL. Anda harus menetapkan nilai default NEWID ().
Perbarui nilai yang ada ke NEWID () di mana NULL sebelum membuat batasan UNIK.
sumber
Apa yang Anda cari memang bagian dari standar ANSI SQL: 92, SQL: 1999 dan SQL: 2003, yaitu batasan UNIK harus melarang duplikat nilai-nilai non-NULL tetapi menerima beberapa nilai NULL.
Dalam dunia Microsoft SQL Server, NULL tunggal diperbolehkan tetapi beberapa NULL tidak ...
Di SQL Server 2008 , Anda dapat menentukan indeks yang difilter unik berdasarkan predikat yang mengecualikan NULLs:
Di versi sebelumnya, Anda dapat menggunakan VIEWS dengan predikat NOT NULL untuk menegakkan batasan.
sumber
SQL Server 2008 Dan Ke Atas
Cukup filter indeks unik:
Dalam Versi Lebih Rendah, Tampilan Terwujud Masih Tidak Diperlukan
Untuk SQL Server 2005 dan sebelumnya, Anda bisa melakukannya tanpa melihat. Saya baru saja menambahkan batasan unik seperti yang Anda minta ke salah satu meja saya. Mengingat bahwa saya ingin keunikan dalam kolom
SamAccountName
, tetapi saya ingin memperbolehkan beberapa NULL, saya menggunakan kolom terwujud daripada tampilan terwujud:Anda hanya perlu meletakkan sesuatu di kolom yang dihitung yang akan dijamin unik di seluruh tabel ketika kolom unik yang sebenarnya diinginkan adalah NULL. Dalam hal ini,
PartyID
adalah kolom identitas dan menjadi numerik tidak akan pernah cocok dengan ituSamAccountName
, jadi itu berfungsi untuk saya. Anda dapat mencoba metode Anda sendiri — pastikan Anda memahami domain data Anda sehingga tidak ada kemungkinan persimpangan dengan data nyata. Itu bisa sesederhana menambahkan karakter pembeda seperti ini:Bahkan jika
PartyID
suatu hari menjadi non-numerik dan bisa bertepatan denganSamAccountName
, sekarang tidak masalah.Perhatikan bahwa keberadaan indeks termasuk kolom yang dihitung secara implisit menyebabkan setiap hasil ekspresi disimpan ke disk dengan data lain dalam tabel, yang TIDAK mengambil ruang disk tambahan.
Perhatikan bahwa jika Anda tidak ingin indeks, Anda masih dapat menyimpan CPU dengan membuat ekspresi menjadi prakalkulasi ke disk dengan menambahkan kata kunci
PERSISTED
ke akhir definisi ekspresi kolom.Di SQL Server 2008 dan lebih tinggi, pasti gunakan solusi yang difilter jika Anda bisa!
Kontroversi
Harap dicatat bahwa beberapa profesional basis data akan melihat ini sebagai kasus "pengganti NULLs", yang pasti memiliki masalah (sebagian besar disebabkan oleh masalah seputar upaya menentukan kapan sesuatu bernilai nyata atau nilai pengganti untuk data yang hilang) ; ada juga masalah dengan jumlah nilai pengganti non-NULL yang berlipat ganda seperti orang gila).
Namun, saya percaya kasus ini berbeda. Kolom yang dihitung yang saya tambahkan tidak akan pernah digunakan untuk menentukan apa pun. Itu tidak memiliki arti itu sendiri, dan mengkodekan tidak ada informasi yang belum ditemukan secara terpisah di kolom lain yang didefinisikan dengan benar. Seharusnya tidak pernah dipilih atau digunakan.
Jadi, cerita saya adalah bahwa ini bukan NULL pengganti, dan saya berpegang teguh pada itu! Karena kita sebenarnya tidak ingin nilai non-NULL untuk tujuan apa pun selain untuk menipu
UNIQUE
indeks agar mengabaikan , kasus penggunaan kami tidak memiliki masalah yang muncul dengan pembuatan NULL pengganti yang normal.Semua yang dikatakan, saya tidak punya masalah dengan menggunakan tampilan yang diindeks sebagai gantinya — tetapi itu membawa beberapa masalah dengan itu seperti persyaratan menggunakan
SCHEMABINDING
. Bersenang-senang menambahkan kolom baru ke tabel basis Anda (Anda minimal harus menjatuhkan indeks, dan kemudian meninggalkan tampilan atau mengubah tampilan agar tidak terikat skema). Lihat daftar lengkap (panjang) persyaratan untuk membuat tampilan yang diindeks di SQL Server (2005) (juga versi yang lebih baru), (2000) .Memperbarui
Jika kolom Anda numerik, mungkin ada tantangan untuk memastikan bahwa penggunaan kendala unik
Coalesce
tidak menghasilkan tabrakan. Dalam hal ini, ada beberapa opsi. Satu mungkin menggunakan angka negatif, untuk menempatkan "pengganti NULLs" hanya di kisaran negatif, dan "nilai nyata" hanya di kisaran positif. Sebagai alternatif, pola berikut dapat digunakan. Dalam tabelIssue
(di manaIssueID
adaPRIMARY KEY
), mungkin ada atau tidak adaTicketID
, tetapi jika ada, itu harus unik.Jika IssueID 1 memiliki tiket 123, batasannya
UNIQUE
adalah nilai (123, NULL). Jika IssueID 2 tidak memiliki tiket, tiket tersebut akan aktif (NULL, 2). Beberapa pemikiran akan menunjukkan bahwa batasan ini tidak dapat diduplikasi untuk setiap baris dalam tabel, dan masih memungkinkan beberapa NULL.sumber
Untuk orang-orang yang menggunakan Microsoft SQL Server Manager dan ingin membuat indeks unik tetapi tidak dapat dibatalkan, Anda dapat membuat indeks unik seperti biasa di indeks properti Anda untuk indeks baru, pilih "Filter" dari panel sebelah kiri, lalu masukkan filter Anda (yang merupakan klausa tempat Anda). Seharusnya membaca sesuatu seperti ini:
Ini berfungsi dengan MSSQL 2012
sumber
Ketika saya menerapkan indeks unik di bawah ini:
setiap pembaruan dan penyisipan non null gagal dengan kesalahan di bawah ini:
Saya menemukan ini di MSDN
Jadi agar ini berfungsi dengan benar, saya melakukan ini
Saya percaya adalah mungkin untuk mengatur opsi ini menggunakan kode
tetapi saya belum menguji ini
sumber
Buat tampilan yang hanya memilih non-
NULL
kolom dan buatUNIQUE INDEX
pada tampilan:Perhatikan bahwa Anda harus melakukan
INSERT
danUPDATE
pada tampilan, bukan pada tabel.Anda dapat melakukannya dengan
INSTEAD OF
pemicu:sumber
Itu bisa dilakukan pada perancang juga
Klik kanan pada Index> Properties untuk mendapatkan jendela ini
sumber
Dimungkinkan untuk membuat batasan unik pada Clustered Indexed View
Anda dapat membuat tampilan seperti ini:
dan kendala unik seperti ini:
sumber
Mungkin pertimbangkan
INSTEAD OF
pemicu dan lakukan pengecekan sendiri? Dengan indeks non-cluster (non-unik) pada kolom untuk mengaktifkan pencarian.sumber
Seperti yang dinyatakan sebelumnya, SQL Server tidak mengimplementasikan standar ANSI ketika datang ke
UNIQUE CONSTRAINT
. Ada tiket di Microsoft Connect untuk ini sejak 2007. Seperti yang disarankan di sana dan di sini opsi terbaik pada hari ini adalah menggunakan indeks yang difilter sebagaimana dinyatakan dalam jawaban lain atau kolom yang dihitung, misalnya:sumber
Anda dapat membuat BUKAN pemicu untuk memeriksa kondisi dan kesalahan tertentu jika terpenuhi. Membuat indeks bisa mahal pada tabel yang lebih besar.
Ini sebuah contoh:
sumber
Anda tidak bisa melakukan ini dengan
UNIQUE
kendala, tetapi Anda bisa melakukan ini di pemicu.sumber
sumber
kode ini jika Anda membuat formulir pendaftaran dengan textBox dan gunakan masukkan dan ur textBox Anda kosong dan Anda klik tombol kirim.
sumber