Secara teknis, NULL = NULL adalah False, dengan logika itu tidak ada NULL yang sama dengan NULL dan semua NULL berbeda. Tidakkah seharusnya ini menyiratkan bahwa semua NULL adalah unik dan indeks unik harus memungkinkan sejumlah NULL?
Secara teknis, NULL = NULL adalah False, dengan logika itu tidak ada NULL yang sama dengan NULL dan semua NULL berbeda. Tidakkah seharusnya ini menyiratkan bahwa semua NULL adalah unik dan indeks unik harus memungkinkan sejumlah NULL?
Jawaban:
Mengapa bisa seperti ini? Karena pada saat itu, seseorang membuat keputusan desain tanpa mengetahui atau peduli tentang apa yang dikatakan standar (setelah semua, kita memang memiliki semua jenis perilaku aneh dengan NULL
, dan dapat memaksa perilaku yang berbeda sesuka hati). Keputusan itu menentukan bahwa, dalam hal ini NULL = NULL
,.
Itu bukan keputusan yang sangat cerdas. Apa yang seharusnya mereka lakukan adalah memiliki perilaku default yang mematuhi standar ANSI, dan jika mereka benar-benar menginginkan perilaku aneh ini, ijinkan itu melalui opsi DDL seperti WITH CONSIDER_NULLS_EQUAL
atau WITH ALLOW_ONLY_ONE_NULL
.
Tentu saja, 20-20 adalah belakang.
Dan kami memiliki solusi, sekarang, bagaimanapun, bahkan jika itu bukan yang terbersih atau paling intuitif.
Anda bisa mendapatkan perilaku ANSI yang tepat di SQL Server 2008 dan di atasnya dengan membuat indeks yang unik dan difilter.
CREATE UNIQUE INDEX foo ON dbo.bar(key) WHERE key IS NOT NULL;
Ini memungkinkan lebih dari satu NULL
nilai karena baris-baris tersebut sama sekali tidak disertakan dalam pemeriksaan duplikat. Sebagai bonus tambahan, ini akan menjadi indeks yang lebih kecil dari satu yang terdiri dari seluruh tabel jika beberapa NULL
s diizinkan (terutama ketika itu bukan satu-satunya kolom dalam indeks, memiliki INCLUDE
kolom, dll). Namun, Anda mungkin ingin mengetahui beberapa batasan lain dari indeks yang difilter:
Benar. Penerapan kendala atau indeks unik di server sql memungkinkan satu dan hanya satu NULL. Benar juga bahwa ini secara teknis tidak sesuai dengan definisi NULL tetapi itu adalah salah satu hal yang mereka lakukan untuk membuatnya lebih berguna walaupun itu "secara teknis" tidak benar. Perhatikan KUNCI UTAMA (juga indeks unik) tidak memungkinkan NULL (tentu saja).
Pertama - berhenti menggunakan frasa "Nilai kosong", itu hanya akan membuat Anda tersesat. Alih-alih, gunakan frasa "penanda nol" - penanda di kolom yang menunjukkan bahwa nilai aktual di kolom ini hilang atau tidak dapat diterapkan (tetapi perhatikan bahwa penanda tidak mengatakan opsi mana yang sebenarnya merupakan kasus¹).
Sekarang, bayangkan berikut ini (di mana basis data tidak memiliki pengetahuan lengkap tentang situasi yang dimodelkan).
Situation Database
ID Code ID Code
-- ----- -- -----
1 A 1 A
2 B 2 (null)
3 C 3 C
4 B 4 (null)
Aturan integritas yang kami modelkan adalah "Kode harus unik". Situasi dunia nyata melanggar ini, jadi database seharusnya tidak membiarkan kedua item 2 dan 4 berada di tabel pada saat yang sama.
Pendekatan teraman, dan paling tidak fleksibel, adalah dengan melarang penanda nol di bidang Kode, sehingga tidak ada kemungkinan data tidak konsisten. Pendekatan yang paling fleksibel adalah dengan memungkinkan beberapa penanda nol dan khawatir tentang keunikan ketika nilai dimasukkan.
Programmer Sybase menggunakan pendekatan yang agak aman, tidak terlalu fleksibel dengan hanya mengizinkan satu penanda nol di tabel - sesuatu yang dikeluhkan oleh komentator sejak saat itu. Microsoft telah melanjutkan perilaku ini, saya kira untuk kompatibilitas ke belakang.
¹ Saya yakin saya membaca suatu tempat yang Codd pertimbangkan untuk mengimplementasikan dua penanda nol - satu untuk tidak diketahui, satu untuk tidak dapat diterapkan - tetapi menolaknya, tetapi saya tidak dapat menemukan referensi. Apakah saya mengingat dengan benar?
PS Kutipan favorit saya tentang null: Louis Davidson, "Desain Database SQL Server 2000 Profesional", Wrox Press, 2001, halaman 52. "Dididihkan menjadi satu kalimat: NULL itu jahat."
null
pun tidak mencapai tujuan ini. Karena nilai yang hilang mungkin ternyata sama dengan nilai di salah satu baris lainnya.
CHECK (Value IN ('A','B','C','D'))
? Kemudian implementasi SQL-Server dan standar SQL memungkinkan tabel untuk memiliki 5 baris (satu baris untuk setiap nilai ditambah 1 dengan NULL.) Kemudian, sementara database konsisten dengan kendala, itu tidak konsisten dengan maksud perancang untuk tabel memiliki maksimal 4 baris. Tidak ada nilai yang NULL dapat diubah menjadi yang tidak akan melanggar kendala, kecuali satu atau lebih baris dihapus.
CREATE TABLE #T(A INT NULL UNIQUE);INSERT INTO #T VALUES (1),(NULL);UPDATE #T SET A = 1 WHERE A IS NULL;
akan memunculkan kesalahan. Menurut teori motivasi desain Anda, Anda harus mencegah penyisipan NULL
dalam kasus pertama - karena pengetahuan yang tidak lengkap berarti tidak ada jaminan bahwa nilainya berbeda.
Ini mungkin tidak akurat secara teknis, tetapi secara filosofis itu membantu saya tidur di malam hari ...
Seperti beberapa yang dikatakan atau disinggung, jika Anda menganggap NULL sebagai tidak dikenal, maka Anda tidak dapat menentukan apakah satu nilai NULL sebenarnya sama dengan nilai NULL lainnya. Berpikir seperti ini, ekspresi NULL == NULL harus dievaluasi menjadi NULL, artinya tidak diketahui.
Batasan unik akan membutuhkan nilai definitif untuk perbandingan nilai kolom. Dengan kata lain, ketika membandingkan nilai kolom tunggal terhadap nilai kolom lainnya menggunakan operator kesetaraan, itu harus bernilai false agar valid. Tidak diketahui tidak benar-benar salah meskipun sering dianggap sebagai kesalahan. Dua nilai NULL bisa sama, atau tidak ... itu tidak bisa ditentukan secara definitif.
Ini membantu untuk memikirkan kendala unik sebagai membatasi nilai-nilai yang dapat ditentukan berbeda satu sama lain. Yang saya maksud dengan ini adalah jika Anda menjalankan SELECT yang terlihat seperti ini:
SELECT * from dbo.table1 WHERE ColumnWithUniqueContraint="some value"
Kebanyakan orang akan mengharapkan satu hasil, mengingat bahwa ada kendala unik. Jika Anda mengizinkan beberapa nilai NULL di ColumnWithUniqueConstraint, maka tidak mungkin untuk memilih satu baris berbeda dari tabel menggunakan NULL sebagai nilai yang dibandingkan.
Mengingat itu, saya percaya bahwa terlepas dari apakah itu diterapkan secara akurat atau tidak sehubungan dengan definisi NULL, itu pasti jauh lebih praktis dalam kebanyakan situasi daripada membiarkan beberapa nilai NULL.
Salah satu tujuan utama dari UNIQUE
kendala adalah untuk mencegah rekaman duplikat. Jika seseorang perlu memiliki tabel di mana ada beberapa catatan di mana nilai "tidak diketahui", tetapi tidak ada dua catatan yang diizinkan memiliki nilai "diketahui" yang sama, maka nilai yang tidak diketahui harus ditugaskan pengidentifikasi unik buatan sebelum mereka ditambahkan ke tabel.
Ada beberapa kasus langka di mana kolom yang memiliki UNIQUE
batasan dan berisi nilai nol tunggal; misalnya, jika tabel berisi pemetaan antara nilai kolom dan deskripsi teks lokal, baris untuk NULL
akan memungkinkan untuk menentukan deskripsi yang akan muncul ketika kolom itu di beberapa tabel lainnya NULL
. Perilaku NULL
memungkinkan untuk kasus penggunaan itu.
Kalau tidak, saya tidak melihat dasar untuk database dengan UNIQUE
batasan pada kolom apa pun untuk memungkinkan adanya banyak catatan yang identik, tetapi saya tidak melihat cara untuk mencegah itu sementara memungkinkan beberapa catatan yang nilai kuncinya tidak dapat dibedakan. Mendeklarasikan yang NULL
tidak sama dengan dirinya sendiri tidak akan membuat NULL
nilai dibedakan satu sama lain.