ORACLE erlaubt keine NULL-Werte in einer der Spalten, die einen Primärschlüssel enthalten. Es scheint, dass dies auch für die meisten anderen Systeme auf Unternehmensebene gilt.
Gleichzeitig erlauben die meisten Systeme auch eindeutige Einschränkungen für nullfähige Spalten.
Warum können eindeutige Einschränkungen NULL-Werte haben, Primärschlüssel jedoch nicht? Gibt es dafür einen fundamentalen logischen Grund oder handelt es sich eher um eine technische Einschränkung?
database
database-design
Roman Starkov
quelle
quelle
Antworten:
Primärschlüssel dienen zur eindeutigen Identifizierung von Zeilen. Dazu werden alle Teile eines Schlüssels mit der Eingabe verglichen.
Per Definition kann NULL nicht Teil eines erfolgreichen Vergleichs sein. Auch ein Vergleich mit sich selbst (
NULL = NULL
) wird fehlschlagen. Dies bedeutet, dass ein Schlüssel mit NULL nicht funktioniert.Zusätzlich ist NULL in einem Fremdschlüssel zulässig, um eine optionale Beziehung zu markieren. (*) Wenn Sie es auch in der PK zulassen, wird dies beschädigt.
(*) Ein Wort der Vorsicht: Nullfähige Fremdschlüssel sind kein sauberes relationales Datenbankdesign.
Wenn es zwei Entitäten gibt
A
undB
aufA
die optional Bezug genommen werden kann,B
besteht die saubere Lösung darin, eine Auflösungstabelle zu erstellen (sagen wirAB
). Diese Tabelle würde verknüpfenA
mitB
: Wenn es ist eine Beziehung , dann würde es einen Datensatz enthalten, wenn es nicht ist , dann wäre es nicht.quelle
Ein Primärschlüssel definiert einen eindeutigen Bezeichner für jede Zeile in einer Tabelle: Wenn eine Tabelle einen Primärschlüssel hat, haben Sie eine garantierte Möglichkeit, eine beliebige Zeile daraus auszuwählen.
Eine eindeutige Einschränkung identifiziert nicht unbedingt jede Zeile. es gibt nur , dass , wenn ein Zeilenwert in ihren Spalten hat, dann müssen sie eindeutig sein. Dies reicht nicht aus, um jede Zeile eindeutig zu identifizieren , was ein Primärschlüssel tun muss.
quelle
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:
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:
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ürdeBOTTOM
Art nebenNULL
die Gewohnheit beiläufig conflating die Semantik von „no value“ mit „unbekanntem Wert“ zu verhindern. ]]quelle
NULL == NULL -> false (zumindest in DBMS)
Sie könnten also auch mit zusätzlichen Spalten mit realen Werten keine Beziehungen mit einem NULL-Wert abrufen.
quelle
where pk_1 = 'a' and pk_2 = 'b'
mit normalen Werten verwenden und zu wechseln,where pk_1 is null and pk_2 = 'b'
wenn Nullen vorhanden sind.where (a.pk1 = b.pk1 or (a.pk1 is null and b.pk1 is null)) and (a.pk2 = b.pk2 or (a.pk2 is null and b.pk2 is null))
/Die Antwort von Tony Andrews ist anständig. Die eigentliche Antwort ist jedoch, dass dies eine Konvention ist, die von der relationalen Datenbankgemeinschaft verwendet wird und KEINE Notwendigkeit ist. Vielleicht ist es eine gute Konvention, vielleicht auch nicht.
Wenn Sie etwas mit NULL vergleichen, erhalten Sie UNBEKANNT (3. Wahrheitswert). Wie bei Nullen vorgeschlagen wurde, geht jede traditionelle Weisheit in Bezug auf Gleichheit aus dem Fenster. So scheint es auf den ersten Blick.
Aber ich denke nicht, dass dies unbedingt so ist, und selbst SQL-Datenbanken glauben nicht, dass NULL alle Vergleichsmöglichkeiten zerstört.
Führen Sie in Ihrer Datenbank die Abfrage SELECT * FROM VALUES (NULL) aus. UNION SELECT * FROM VALUES (NULL)
Was Sie sehen, ist nur ein Tupel mit einem Attribut, das den Wert NULL hat. Die Union hat hier also die beiden NULL-Werte als gleich erkannt.
Beim Vergleich eines zusammengesetzten Schlüssels mit 3 Komponenten mit einem Tupel mit 3 Attributen (1, 3, NULL) = (1, 3, NULL) <=> 1 = 1 UND 3 = 3 UND NULL = NULL Das Ergebnis ist UNBEKANNT .
Wir könnten aber eine neue Art von Vergleichsoperator definieren, z. ==. X == Y <=> X = Y ODER (X IST NULL UND Y IST NULL)
Ein solcher Gleichheitsoperator würde zusammengesetzte Schlüssel mit Nullkomponenten oder nicht zusammengesetzte Schlüssel mit Nullwerten unproblematisch machen.
quelle
Ich glaube immer noch, dass dies ein grundlegender / funktionaler Fehler ist, der durch eine technische Tatsache verursacht wird. Wenn Sie ein optionales Feld haben, anhand dessen Sie einen Kunden identifizieren können, müssen Sie jetzt einen Dummy-Wert in diesen hacken, nur weil NULL! = NULL, nicht besonders elegant, aber ein "Industriestandard".
quelle