Secara mendasar tidak ada yang salah dengan NULL dalam kunci utama multi-kolom. Tetapi memiliki satu implikasi yang kemungkinan tidak diinginkan oleh perancang, itulah sebabnya banyak sistem membuat kesalahan ketika Anda mencoba ini.
Pertimbangkan kasus versi modul / paket yang disimpan sebagai serangkaian bidang:
CREATE TABLE module
(name varchar(20) PRIMARY KEY,
description text DEFAULT '' NOT NULL);
CREATE TABLE version
(module varchar(20) REFERENCES module,
major integer NOT NULL,
minor integer DEFAULT 0 NOT NULL,
patch integer DEFAULT 0 NOT NULL,
release integer DEFAULT 1 NOT NULL,
ext varchar(20),
notes text DEFAULT '' NOT NULL,
PRIMARY KEY (module, major, minor, patch, release, ext));
5 elemen pertama dari kunci utama secara teratur didefinisikan sebagai bagian dari versi rilis, tetapi beberapa paket memiliki ekstensi khusus yang biasanya bukan bilangan bulat (seperti "rc-foo" atau "vanilla" atau "beta" atau apa pun yang dilakukan seseorang untuk yang empat bidang tidak mencukupi mungkin bermimpi). Jika sebuah paket tidak memiliki ekstensi, maka itu NULL dalam model di atas, dan tidak ada salahnya dilakukan dengan meninggalkan hal-hal seperti itu.
Tapi apa itu NULL? Seharusnya mewakili kurangnya informasi, tidak diketahui. Yang mengatakan, mungkin ini lebih masuk akal:
CREATE TABLE version
(module varchar(20) REFERENCES module,
major integer NOT NULL,
minor integer DEFAULT 0 NOT NULL,
patch integer DEFAULT 0 NOT NULL,
release integer DEFAULT 1 NOT NULL,
ext varchar(20) DEFAULT '' NOT NULL,
notes text DEFAULT '' NOT NULL,
PRIMARY KEY (module, major, minor, patch, release, ext));
Dalam versi ini bagian "ext" dari tuple BUKAN NULL tetapi default ke string kosong - yang secara semantik (dan praktis) berbeda dari NULL. NULL adalah suatu yang tidak diketahui, sedangkan string kosong adalah catatan yang disengaja dari "sesuatu yang tidak ada". Dengan kata lain, "kosong" dan "nol" adalah hal yang berbeda. Perbedaan antara "Saya tidak punya nilai di sini" dan "Saya tidak tahu apa nilai di sini."
Ketika Anda mendaftarkan paket yang tidak memiliki ekstensi versi, Anda tahu itu tidak memiliki ekstensi, jadi string kosong sebenarnya adalah nilai yang benar. NULL hanya akan benar jika Anda tidak tahu apakah ekstensi itu atau tidak, atau Anda tahu itu ekstensi tetapi tidak tahu apa itu ekstensi. Situasi ini lebih mudah untuk ditangani dalam sistem di mana nilai string adalah norma, karena tidak ada cara untuk mewakili "integer kosong" selain memasukkan 0 atau 1, yang akhirnya akan digulung dalam perbandingan apa pun yang dibuat kemudian (yang memiliki implikasinya sendiri) *.
Kebetulan, kedua cara ini valid di Postgres (karena kita sedang membahas "perusahaan" RDMBSs), tetapi hasil perbandingan dapat sedikit berbeda ketika Anda melempar NULL ke dalam campuran - karena NULL == "tidak tahu" jadi semua hasil perbandingan yang melibatkan NULL akhirnya menjadi NULL karena Anda tidak dapat mengetahui sesuatu yang tidak dikenal. BAHAYA! Pikirkan baik-baik tentang itu: ini berarti bahwa hasil perbandingan NULL menyebar melalui serangkaian perbandingan. Ini bisa menjadi sumber bug halus saat menyortir, membandingkan, dll.
Postgres mengasumsikan Anda sudah dewasa dan dapat mengambil keputusan sendiri. Oracle dan DB2 menganggap Anda tidak menyadari bahwa Anda melakukan sesuatu yang konyol dan membuat kesalahan. Ini biasanya hal yang benar, tetapi tidak selalu - Anda mungkin sebenarnya tidak tahu dan memiliki NULL dalam beberapa kasus dan karenanya meninggalkan baris dengan elemen yang tidak diketahui yang tidak mungkin dilakukan perbandingan yang berarti adalah perilaku yang benar.
Dalam kasus apa pun Anda harus berusaha untuk menghilangkan jumlah bidang NULL yang Anda izinkan di seluruh skema dan dua kali lipat ketika menyangkut bidang yang merupakan bagian dari kunci utama. Dalam sebagian besar kasus, keberadaan kolom NULL merupakan indikasi rancangan skema yang tidak dinormalisasi (berlawanan dengan yang tidak dinormalisasi dengan sengaja) dan harus dipikirkan dengan keras sebelum diterima.
[* CATATAN: Dimungkinkan untuk membuat tipe khusus yang merupakan gabungan bilangan bulat dan tipe "bawah" yang secara semantik berarti "kosong" sebagai kebalikan dari "tidak dikenal". Sayangnya ini memperkenalkan sedikit kompleksitas dalam operasi perbandingan dan biasanya benar-benar mengetik benar tidak sepadan dengan usaha dalam praktik karena Anda tidak boleh diizinkan banyak NULL
nilai sama sekali di tempat pertama. Yang mengatakan, akan luar biasa jika RDBMS akan memasukkan BOTTOM
tipe standar selain NULL
untuk mencegah kebiasaan santai semantik semantik "tidak ada nilai" dengan "nilai tidak diketahui". ]