SQL-Server: Warum liefert der Vergleich null=Wert true zurück, für NICHT?

Warum spielt der Vergleich von value zu null false zurück, außer bei Verwendung eines NOT IN, wo gibt es true zurück?


Gegeben, eine Abfrage aller stackoverflow-Benutzer, die haben post:

SELECT * FROM Users
WHERE UserID IN (SELECT UserID FROM Posts)

Diese wie erwartet funktioniert; bekomme ich eine Liste aller Benutzer, die ein post.

Nun die Abfrage für die inverse, finden Sie alle stackoverflow-Benutzer, die nicht post:

SELECT * FROM Users
WHERE UserID NOT IN (SELECT UserID FROM Posts)

Diesem keine Datensätze zurückgibt, was falsch ist.

Gegeben hypothetischen Daten1

Users              Posts
================   ===============================
UserID  Username   PostID   UserID  Subject
------  --------   -------  ------  ----------------
1       atkins     1        1       Welcome to stack ov...
2       joels      2        2       Welcome all!
...     ...        ...      ...
399573  gt6989b    ...      ...
...     ...        ...      ...
                   10592    null    (deleted by nsl&fbi...
                   ...      ... 

Übernehmen und die Regeln des Null-Werte:

  • NULL = NULL mit unknown ausgewertet
  • NULL <> NULL mit unknown ausgewertet
  • value = NULL wertet unbekannt

Wenn wir uns auf die 2. Abfrage, die uns interessiert, findet alle Zeilen, in denen die Benutzer.UserID ist nicht gefunden in den Beiträgen.UserID-Spalte. ich würde gehen logischerweise wie folgt:

Check UserID 1

  • 1 = 1 gibt true zurück. So können wir daraus folgern, dass dieser Benutzer hat einige posts, und schließen Sie Sie nicht in die Ausgabe-Liste

Überprüfen Sie nun, UserID, 2:

  • 2 = 1 gibt false zurück, so halten wir auf der Suche
  • 2 = 2 gibt true zurück, so können wir daraus folgern, dass dieser Benutzer hat einige posts, und schließen Sie Sie nicht in die Ausgabe-Liste

Überprüfen Sie nun, UserID 399573

  • 399573 = 1 gibt false zurück, so halten wir auf der Suche
  • 399573 = 2 gibt false zurück, so halten wir auf der Suche
  • ...
  • 399573 = null gibt unbekannt ist, so halten wir auf der Suche
  • ...

Wir fanden keine Beiträge UserID 399573, so würden wir mit ihm in der output-Liste.

Außer SQL Server dies nicht tut. Wenn Sie eine NULL in Ihrem in Liste, dann plötzlich, es findet eine übereinstimmung. Es plötzlich eine übereinstimmung findet. Plötzlich 399573 = null zu true ausgewertet wird.

Warum spielt der Vergleich von value zu null Rückkehr unbekannt, außer, wenn es zurück wahr?

Bearbeiten: ich weiß, dass ich dies umgehen unsinnig Verhalten unter Ausschluss der null-Werte:

SELECT * FROM Users
WHERE UserID NOT IN (
   SELECT UserID FROM Posts
   WHERE UserID IS NOT NULL)

Aber ich sollte nicht zu haben, soweit ich das sagen kann, der booleschen Logik sollte in Ordnung sein, ohne Sie - daher meine Frage.

Fußnoten

  • 1 hypothetische Daten; wenn Sie es nicht mögen: machen Sie Ihr nach unten.
  • celko hat nun seinen eigenen tag
  • Duplizieren: Siehe stackoverflow.com/questions/129077/...
  • ich sehe. Es ist nicht darauf hingewiesen die andere Frage - aber es ist ein bug, wie die NOT IN erweitert wird. Anstatt logisch zu bestimmen, ob die Zeile "nicht in" die Liste, es erweitert es um eine Reihe von and <> Klauseln.
  • Boyd = ich denke nicht, dass das ein bug ist. Etwas anderes zu erinnern ist IN verwendet or und NOT IN verwendet AND. Wenn Sie die Auswertung gegen eine NULL mit eine Ungleichheit im Vergleich zu einem bekannten Wert, bekommen Sie immer falsch, da es keine Möglichkeit gibt zu wissen, ob es passt oder nicht.
  • Boyd: ich würde nicht nennen dies ein Fehler. IN ist nichts mehr als eine praktische Abkürzung für eine Reihe von OR Klauseln. Technisch gesehen, der richtige Weg zu denken, der ausbau in die andere Frage ist: select 'true' where NOT(3 = 1 or 3 = 2 or 3 = null), das ist logisch äquivalent von DeMorgan ' s Law. In jedem Fall, der Trugschluss ist die Annahme, dass ein Vergleich von einem Wert=NULL Wert FALSE zurück, wenn in der Tat das Ergebnis UNBEKANNT ist.
  • Yep. Kein Fehler ist. Auch ist es nicht booleschen Logik. Es ist 3 bewertet logic.
  • Joe Stefanelli: das ist das problem. Konvertieren IN zu or, und NOT IN zu and ändert sich die logische Bedeutung.
  • Boyd - Nein, logisch eine Liste von Werten für eine IN Klausel SOLLTE sich die Evaluierung auf eine Reihe von OR Aussagen. Die NOT IN auch logisch ausgewertet, um eine Serie von AND Aussagen. Was fragst du, wenn du fragst, ob ein Wert NOT IN (a,b,c,d) als zu sagen, es ist NOT a, NOT b, NOT c, AND ALSO NOT d?
  • "ich denke über das naming meiner Tochter Kirsten, aber nur, wenn keiner meiner Freunde haben eine Schwester mit dem Namen Kirsten. Die Namen von mein Freund der Schwestern sind: Nicholle, Joanne ich nicht, habe eine Schwester, Sherry. Ausgezeichnete, Kirsten ist not in die Liste der Namen. Einige math-geek drehte es in der booleschen algebra wird die falsche Antwort, dann sagt er, dass die Frage selbst ist fehlerhaft. Das ist in Ordnung, aber Fragen Sie irgendjemanden, der Abschluss der 8. Klasse, welche Antwort richtig ist. Aber egal: ich habe die Antwort auf meine Frage: NOT IN bedeutet nicht NOT IN es bedeutet and <> ... and <> ... and <>.
  • Betrachten Sie auch den Algorithmus, den ich in der ursprünglichen Frage zu bewerten NOT IN - das ist das, was jeder vernünftige Mensch tun würde, wenn gefragt wird, ob Kirsten ist nicht in ( Nicholle , Joanne ich nicht, habe eine Schwester, Sherry). Datenbank-engine Designer wählte darstellen NOT IN als and <> and <> and <>, was in Ordnung ist.
  • Stefanelli "ist nichts weiter als eine praktische Abkürzung für etwas anderes. Meine Verwirrung war, dass ich dachte not in gemeint not in ich wusste nicht, es war eine Abkürzung für eine Reihe von and <>. Einmal definiert wurde: die Ergebnisse, die ich sehen, macht Sinn.
  • Boyd - Für Ihre Schwester-name-Problem, das ist eine Daten-Modellierung Problem. Sie sollten über eine Untertabelle SISTER bezieht sich Sie zurück zu Ihrem Haupt-Tabelle. Wenn Sie nicht eine Schwester haben, Sie wäre nicht in die Ergebnismenge aufgenommen. Auch NULL bedeutet unbekannt. Wenn Sie haben 2 Leute, deren Namen Sie nicht kennen, können Sie sagen Ihre Namen nicht, Kirsten?
  • Du denkst wie ein computer-Wissenschaftler, die das Gegenteil von dem ein normaler Mensch.
  • Boyd - Deine Schwester z.B. würde so funktionieren, wie Sie erwarten, wenn Sie eine nicht-ANSI-null-Wert, wie eine leere Zeichenfolge (als dummy-null-Wert, nicht wirklich null ist)--oder ausschalten ANSI_NULLS -, natürlich. Aber dein Beispiel ist auch nicht voraussehen, mehrere Schwestern (ich bin mir nicht sicher, ob das Modell vorgeschlagen von @JNK nicht, entweder). Wenn Sie eine Zeile für jede Schwester mit einem fremden Schlüssel zurück an den entsprechenden Freund finde ich die entsprechende Abfrage, die Sie würde dann-Konstrukt mit einem INNER JOIN korrekt, ignorieren Sie Freunde mit keine Schwestern und produzieren die richtige Liste mit Namen die keine null-Werte in es.

InformationsquelleAutor Ian Boyd | 2010-10-13
Schreibe einen Kommentar