Grundsätzlich ist mit einem NULL in einem mehrspaltigen Primärschlüssel nichts falsch. Aber eine zu haben hat Auswirkungen, die der Designer wahrscheinlich nicht beabsichtigt hat, weshalb viele Systeme einen Fehler auslösen, wenn Sie dies versuchen.
Betrachten Sie den Fall von Modul- / Paketversionen, die als eine Reihe von Feldern gespeichert sind:
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));
Die ersten 5 Elemente des Primärschlüssels sind regelmäßig definierte Teile einer Release-Version, aber einige Pakete haben eine angepasste Erweiterung, die normalerweise keine Ganzzahl ist (wie "rc-foo" oder "vanilla" oder "beta" oder was auch immer jemand anderes für wen vier Felder nicht ausreichen, könnte man sich ausdenken). Wenn ein Paket keine Erweiterung hat, ist es im obigen Modell NULL, und es würde keinen Schaden anrichten, wenn die Dinge so bleiben.
Aber was ist ein NULL? Es soll einen Mangel an Informationen darstellen, ein Unbekannter. Das heißt, vielleicht macht das mehr Sinn:
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));
In dieser Version ist der "ext" -Teil des Tupels NICHT NULL, sondern standardmäßig eine leere Zeichenfolge - die sich semantisch (und praktisch) von einer NULL unterscheidet. Ein NULL ist ein Unbekannter, während ein leerer String eine absichtliche Aufzeichnung von "etwas, das nicht vorhanden ist" ist. Mit anderen Worten, "leer" und "null" sind verschiedene Dinge. Es ist der Unterschied zwischen "Ich habe hier keinen Wert" und "Ich weiß nicht, was der Wert hier ist".
Wenn Sie ein Paket registrieren, dem eine Versionserweiterung fehlt, wissen Sie, dass ihm eine Erweiterung fehlt. Daher ist eine leere Zeichenfolge tatsächlich der richtige Wert. Ein NULL wäre nur dann richtig, wenn Sie nicht wüssten, ob es eine Erweiterung hat oder nicht, oder wenn Sie wüssten, dass dies der Fall ist, aber nicht wissen, was es ist. Diese Situation ist in Systemen, in denen Zeichenfolgenwerte die Norm sind, einfacher zu handhaben, da es keine andere Möglichkeit gibt, eine "leere Ganzzahl" darzustellen, als 0 oder 1 einzufügen, die bei später durchgeführten Vergleichen aufgerollt wird (was der Fall ist) seine eigenen Implikationen) *.
Übrigens sind beide Möglichkeiten in Postgres gültig (da es sich um "Enterprise" -RDMBSs handelt), aber die Vergleichsergebnisse können erheblich variieren, wenn Sie einen NULL in die Mischung werfen - weil NULL == "weiß nicht" also alle Ergebnisse eines Vergleichs mit NULL werden NULL, da Sie nichts Unbekanntes wissen können. ACHTUNG! Überlegen Sie genau , dass: Das bedeutet , dass NULL Vergleichsergebnisse propagieren durch eine Reihe von Vergleichen. Dies kann zu subtilen Fehlern beim Sortieren, Vergleichen usw. führen.
Postgres geht davon aus, dass Sie erwachsen sind und diese Entscheidung selbst treffen können. Oracle und DB2 gehen davon aus, dass Sie nicht bemerkt haben, dass Sie etwas Dummes getan haben, und werfen einen Fehler. Dies ist in der Regel das Richtige, aber nicht immer - Sie könnten eigentlich nicht wissen , und eine NULL in einigen Fällen haben und daher eine Reihe mit einem unbekannten Element verlassen , gegen die sinnvolle Vergleiche sind nicht das richtige Verhalten ist.
In jedem Fall sollten Sie sich bemühen, die Anzahl der NULL-Felder, die Sie im gesamten Schema zulassen, zu eliminieren, und zwar doppelt, wenn es um Felder geht, die Teil eines Primärschlüssels sind. In den allermeisten Fällen ist das Vorhandensein von NULL-Spalten ein Hinweis auf ein nicht normalisiertes (im Gegensatz zu einem absichtlich de-normalisierten) Schemadesign und sollte vor der Annahme sehr gründlich überlegt werden.
[* HINWEIS: Es ist möglich, einen benutzerdefinierten Typ zu erstellen, der die Vereinigung von Ganzzahlen und einen "unteren" Typ darstellt, der semantisch "leer" im Gegensatz zu "unbekannt" bedeutet. Leider führt dies zu einer gewissen Komplexität bei Vergleichsoperationen, und normalerweise lohnt es sich in der Praxis nicht, wirklich typkorrekt zu sein, da Ihnen überhaupt nicht viele NULL
Werte erlaubt sein sollten . Das sei gesagt, es wäre schön, wenn RDBMS eine Standard umfassen würde BOTTOM
Art neben NULL
die Gewohnheit beiläufig conflating die Semantik von „no value“ mit „unbekanntem Wert“ zu verhindern. ]]