Technisch gesehen ist NULL = NULL Falsch. Nach dieser Logik ist kein NULL-Wert gleich einem NULL-Wert und alle NULL-Werte sind unterschiedlich. Sollte dies nicht bedeuten, dass alle NULL-Werte eindeutig sind und ein eindeutiger Index eine beliebige Anzahl von NULL-Werten zulassen sollte?
36
Antworten:
Warum funktioniert das so? Denn vor langer Zeit traf jemand eine Entwurfsentscheidung, ohne zu wissen oder sich darum zu kümmern, was der Standard sagt (schließlich haben wir alle möglichen seltsamen Verhaltensweisen mit
NULL
s und können nach Belieben ein anderes Verhalten erzwingen). Diese Entscheidung diktierte, dass in diesem FallNULL = NULL
.Es war keine sehr kluge Entscheidung. Was sie getan haben sollten, ist, dass das Standardverhalten dem ANSI-Standard entspricht, und wenn sie dieses besondere Verhalten wirklich wollten, lassen Sie es durch eine DDL-Option wie
WITH CONSIDER_NULLS_EQUAL
oder zuWITH ALLOW_ONLY_ONE_NULL
.Natürlich ist im Nachhinein 20/20.
Und wir haben jetzt sowieso einen Workaround, auch wenn es nicht der sauberste oder intuitivste ist.
Sie können das richtige ANSI-Verhalten in SQL Server 2008 und höher erzielen, indem Sie einen eindeutigen, gefilterten Index erstellen.
Dies ermöglicht mehr als einen
NULL
Wert, da diese Zeilen bei der Duplikatprüfung nicht berücksichtigt werden. Als zusätzlichen Bonus wäre dies ein kleinerer Index als ein Index, der aus der gesamten Tabelle besteht, wenn mehrereNULL
s zulässig wären (insbesondere, wenn es nicht die einzige Spalte im Index ist,INCLUDE
Spalten usw. enthält). Möglicherweise möchten Sie jedoch einige der anderen Einschränkungen von gefilterten Indizes kennen:quelle
Richtig. Die Implementierung einer eindeutigen Einschränkung oder eines eindeutigen Indexes in SQL Server ermöglicht nur einen NULL-Wert. Korrigieren Sie auch, dass dies technisch nicht mit der Definition von NULL übereinstimmt, aber es ist eines der Dinge, die sie getan haben, um es nützlicher zu machen, obwohl es nicht "technisch" korrekt ist. Beachten Sie, dass ein PRIMARY KEY (auch ein eindeutiger Index) (natürlich) keine NULL-Werte zulässt.
quelle
Hören Sie auf, den Ausdruck "Nullwert" zu verwenden, da Sie sonst in die Irre geführt werden. Verwenden Sie stattdessen den Ausdruck "Null-Markierung" - eine Markierung in einer Spalte, die angibt, dass der tatsächliche Wert in dieser Spalte fehlt oder nicht anwendbar ist (beachten Sie jedoch, dass die Markierung nicht angibt, welche dieser Optionen tatsächlich der Fall ist¹).
Stellen Sie sich nun Folgendes vor (wobei die Datenbank die modellierte Situation nicht vollständig kennt).
Die Integritätsregel, die wir modellieren, lautet "Der Code muss eindeutig sein". Die reale Situation verstößt dagegen, sodass die Datenbank nicht zulässt, dass sich die Elemente 2 und 4 gleichzeitig in der Tabelle befinden.
Der sicherste und am wenigsten flexible Ansatz besteht darin, Nullmarkierungen im Feld Code nicht zuzulassen, sodass keine inkonsistenten Daten möglich sind. Der flexibelste Ansatz besteht darin, mehrere Nullmarken zuzulassen und sich bei der Eingabe von Werten um die Eindeutigkeit zu sorgen.
Die Sybase-Programmierer entschieden sich für den etwas sicheren, nicht sehr flexiblen Ansatz, nur einen Null-Marker in der Tabelle zuzulassen - worüber sich Kommentatoren seitdem beschwert haben. Microsoft hat dieses Verhalten fortgesetzt, ich denke für die Abwärtskompatibilität.
¹ Ich bin mir sicher, dass ich irgendwo gelesen habe, dass Codd überlegt hat, zwei Null-Marker zu implementieren - einen für unbekannt, einen für nicht zutreffend -, diesen aber abgelehnt habe, aber ich kann den Verweis nicht finden. Erinnere ich mich richtig?
PS Mein Lieblingszitat zu null: Louis Davidson, "Professionelles SQL Server 2000-Datenbankdesign", Wrox Press, 2001, Seite 52. "Auf einen einzigen Satz gebracht: NULL ist böse."
quelle
null
erreicht dieses Ziel ebenfalls nicht. Weil sich herausstellen kann, dass der fehlende Wert mit dem Wert in einer der anderen Zeilen übereinstimmt.CHECK (Value IN ('A','B','C','D'))
? Dann erlauben sowohl die Implementierung von SQL-Server als auch der SQL-Standard, dass die Tabelle 5 Zeilen enthält (eine Zeile für jeden Wert plus 1 mit NULL). Während die Datenbank mit ihren Einschränkungen konsistent ist, stimmt sie wohl nicht mit der Absicht des Designers überein Die Tabelle darf maximal 4 Zeilen enthalten. Es gibt keinen Wert, in den NULL geändert werden kann, der keine Einschränkung verletzt, es sei denn, eine oder mehrere Zeilen werden gelöscht.CREATE TABLE #T(A INT NULL UNIQUE);INSERT INTO #T VALUES (1),(NULL);UPDATE #T SET A = 1 WHERE A IS NULL;
wird einen Fehler auslösen. Nach Ihrer Theorie der Gestaltungsmotive hätte das EinfügenNULL
im ersten Fall verhindert werden müssen - denn das unvollständige Wissen bedeutet, dass es keine Garantie dafür gibt, dass der Wert unterschiedlich ist.Das mag technisch nicht korrekt sein, aber philosophisch hilft es mir, nachts zu schlafen ...
Wie mehrere andere gesagt oder angedeutet haben, können Sie, wenn Sie NULL als unbekannt betrachten, nicht feststellen, ob ein NULL-Wert tatsächlich einem anderen NULL-Wert entspricht. Auf diese Weise sollte der Ausdruck NULL == NULL zu NULL ausgewertet werden, was "unbekannt" bedeutet.
Eine eindeutige Einschränkung würde einen endgültigen Wert für den Vergleich der Spaltenwerte benötigen. Mit anderen Worten, wenn ein einzelner Spaltenwert mit einem anderen Spaltenwert unter Verwendung des Gleichheitsoperators verglichen wird, muss er mit false bewertet werden, um gültig zu sein. Unbekannt ist nicht wirklich falsch, obwohl es oft als falsch behandelt wird. Zwei NULL-Werte können gleich sein oder nicht ... sie können einfach nicht definitiv bestimmt werden.
Es ist hilfreich, sich eine eindeutige Einschränkung als einschränkende Werte vorzustellen, bei denen festgestellt werden kann, dass sie sich voneinander unterscheiden. Was ich damit meine ist, wenn Sie ein SELECT ausführen, das ungefähr so aussieht:
Die meisten Menschen würden ein Ergebnis erwarten, da es eine einzigartige Einschränkung gibt. Wenn Sie in ColumnWithUniqueConstraint mehrere NULL-Werte zulassen, ist es unmöglich, eine einzelne Zeile aus der Tabelle auszuwählen, wobei NULL als Vergleichswert verwendet wird.
Angesichts dessen glaube ich, dass es in den meisten Situationen viel praktischer ist, als mehrere NULL-Werte zuzulassen, unabhängig davon, ob es in Bezug auf die Definition von NULL korrekt implementiert ist oder nicht.
quelle
Einer der Hauptzwecke einer
UNIQUE
Einschränkung besteht darin, doppelte Datensätze zu verhindern. Wenn eine Tabelle benötigt wird, in der es mehrere Datensätze geben kann, in denen ein Wert "unbekannt" ist, aber keine zwei Datensätze denselben "bekannten" Wert haben dürfen, sollten den unbekannten Werten künstliche eindeutige Bezeichner zugewiesen werden, bevor sie vorhanden sind zur Tabelle hinzugefügt.Es gibt einige seltene Fälle, in denen eine Spalte eine
UNIQUE
Einschränkung aufweist und einen einzelnen Nullwert enthält. Wenn eine Tabelle beispielsweise eine Zuordnung zwischen Spaltenwerten und lokalisierten Textbeschreibungen enthält, kann in einer Zeile fürNULL
die Beschreibung definiert werden, die angezeigt werden soll, wenn sich diese Spalte in einer anderen Tabelle befindetNULL
. Das Verhalten vonNULL
lässt diesen Anwendungsfall zu.Ansonsten sehe ich keine Grundlage für eine Datenbank mit einer
UNIQUE
Einschränkung für eine Spalte, die das Vorhandensein vieler identischer Datensätze zulässt, aber ich sehe keine Möglichkeit, dies zu verhindern, während mehrere Datensätze zugelassen werden, deren Schlüsselwerte nicht unterscheidbar sind. Wenn Sie angeben, dass diesNULL
nicht mit sich selbstNULL
übereinstimmt, können die Werte nicht voneinander unterschieden werden.quelle