Temel olarak konuşursak, çok sütunlu bir birincil anahtardaki NULL ile hiçbir şey yanlış değildir. Ancak bir tanesine sahip olmak, tasarımcının muhtemelen istemediği sonuçlara sahiptir, bu yüzden bunu denediğinizde birçok sistem hata verir.
Bir dizi alan olarak depolanan modül / paket sürümlerini düşünün:
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));
Birincil anahtarın ilk 5 öğesi, bir yayın sürümünün düzenli olarak tanımlanmış parçalarıdır, ancak bazı paketler genellikle tamsayı olmayan özelleştirilmiş bir uzantıya sahiptir ("rc-foo" veya "vanilya" veya "beta" gibi veya başka biri ne için olursa olsun) kime dört alanları) hayal olabilir yetersizdir. Bir paketin bir uzantısı yoksa yukarıdaki modelde NULL olur ve işleri böyle bırakarak herhangi bir zarar verilmez.
Ama ne olduğunu bir BOŞ? Bilgi eksikliğini , bilinmeyeni temsil etmesi gerekiyordu . Bununla birlikte, belki bu daha mantıklıdır:
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));
Bu versiyonda, başlığın "ext" kısmı NULL DEĞİLDİR, ancak öntanımlı olarak boş bir dizgedir - anlamsal olarak (ve pratik olarak) NULL'dan farklıdır. NULL bilinmeyen bir dizge iken boş dizge "mevcut olmayan bir şeyin" kasıtlı bir kaydıdır. Diğer bir deyişle, "boş" ve "boş" farklı şeylerdir. "Burada bir değerim yok" ile "Buradaki değerin ne olduğunu bilmiyorum" arasındaki fark bu.
Sürüm uzantısı olmayan bir paketi kaydettiğinizde , bir uzantıdan yoksun olduğunu bilirsiniz , bu nedenle boş bir dize aslında doğru değerdir. Bir NULL, yalnızca bir uzantısı olup olmadığını bilmiyorsanız veya ne olduğunu bildiğiniz halde ne olduğunu bilmiyorsanız doğru olacaktır. Dize değerlerinin norm olduğu sistemlerde bu durumla başa çıkmak daha kolaydır, çünkü 0 veya 1 eklemek dışında "boş bir tamsayıyı" temsil etmenin yolu yoktur, bu daha sonra yapılan herhangi bir karşılaştırmada toplanır (ki kendi sonuçları) *.
Bu arada, Postgres'te her iki yol da geçerlidir ("kurumsal" RDMBS'leri tartıştığımız için), ancak karışıma bir NULL attığınızda karşılaştırma sonuçları biraz değişebilir - çünkü NULL == "bilmiyorum" yani hepsi NULL içeren bir karşılaştırmanın sonuçları, bilinmeyen bir şeyi bilemeyeceğiniz için NULL olur. TEHLİKE! Bunu dikkatlice düşünün: Bu, NULL karşılaştırma sonuçlarının bir dizi karşılaştırma yoluyla yayıldığı anlamına gelir . Bu, sıralarken, karşılaştırırken vb. İnce hataların kaynağı olabilir.
Postgres, yetişkin olduğunuzu varsayar ve bu kararı kendiniz verebilir. Oracle ve DB2, aptalca bir şey yaptığınızın farkında olmadığınızı varsayar ve bir hata verir. Bu genellikle doğru olan şeydir, ancak her zaman değil - aslında bilmiyor olabilirsiniz ve bazı durumlarda bir NULL'a sahip olabilirsiniz ve bu nedenle, anlamlı karşılaştırmaların imkansız olduğu bilinmeyen bir öğeyle bir satır bırakmak doğru davranıştır.
Her durumda, tüm şema boyunca izin verdiğiniz NULL alanların sayısını ortadan kaldırmaya çalışmalısınız ve bir birincil anahtarın parçası olan alanlar söz konusu olduğunda bunu iki katına çıkarmalısınız. Vakaların büyük çoğunluğunda, NULL sütunlarının varlığı, normalize edilmemiş (kasıtlı olarak normalleştirilmesinin aksine) şema tasarımının bir göstergesidir ve kabul edilmeden önce çok düşünülmesi gerekir.
[* NOT: Tamsayıların birleşimi olan özel bir tür ve "bilinmeyen" yerine anlamsal olarak "boş" anlamına gelen "alt" bir tür oluşturmak mümkündür. Ne yazık ki bu, karşılaştırma işlemlerinde biraz karmaşıklık getirir ve genellikle gerçekten doğru tipte olmak pratikte çabaya değmez, NULLçünkü ilk başta birçok değere izin verilmemelidir . Bununla birlikte, RDBMS'lerin "değer yok" anlamını "bilinmeyen değer" ile rasgele bir şekilde karıştırma alışkanlığını önlemek için varsayılan bir BOTTOMtür içermesi harika olurdu NULL. ]