Nicht gleich <>! = Operator auf NULL

271

Könnte jemand bitte das folgende Verhalten in SQL erklären?

SELECT * FROM MyTable WHERE MyColumn != NULL (0 Results)
SELECT * FROM MyTable WHERE MyColumn <> NULL (0 Results)
SELECT * FROM MyTable WHERE MyColumn IS NOT NULL (568 Results)
Maxim Gershkovich
quelle

Antworten:

308

<>ist Standard SQL-92; !=ist das Äquivalent. Beide bewerten nach Werten, was NULLnicht - NULList ein Platzhalter, um zu sagen, dass kein Wert vorhanden ist.

Deshalb können Sie IS NULL/ nur IS NOT NULLals Prädikate für solche Situationen verwenden.

Dieses Verhalten ist nicht spezifisch für SQL Server. Alle standardkonformen SQL-Dialekte funktionieren auf die gleiche Weise.

Hinweis : Zum Vergleichen, wenn Ihr Wert nicht null ist , verwenden Sie IS NOT NULL, während Sie zum Vergleichen mit dem Wert nicht null verwenden <> 'YOUR_VALUE'. Ich kann nicht sagen, ob mein Wert gleich oder nicht gleich NULL ist, aber ich kann sagen, ob mein Wert NULL oder NICHT NULL ist. Ich kann vergleichen, ob mein Wert etwas anderes als NULL ist.

OMG Ponys
quelle
4
Eigentlich glaube ich, <>dass es in der 92-Spezifikation ist, aber die meisten Anbieter unterstützen !=und / oder es ist in einer späteren Spezifikation wie 99 oder 03 enthalten.
Thomas
2
@Thomas: Oracle hat, !=wie ich verstehe, bis ~ 9i nicht unterstützt , was eine Menge ANSI-92-Syntax mit sich brachte. Meiner Meinung nach ist MySQL ähnlich und startet die Unterstützung in 4.x.
OMG Ponys
Dies scheint darauf hinzudeuten, dass !=dies in einer späteren Spezifikation als Alternative zu enthalten sein könnte <>. Ich habe keine neuen Spezifikationen in den Händen, daher kann ich nicht sicher sagen.
Thomas
2
Ist das Ergebnis von WHERE MyColumn != NULLoder WHERE MyColumn = NULLdeterministisch? Oder wird mit anderen Worten garantiert immer 0 Zeilen zurückgegeben, unabhängig davon, ob sie MyColumnin der Datenbank nullwertfähig sind oder nicht?
Slauma
11
Es sollte auch beachtet werden, dass, wenn !=nur Werte ausgewertet werden, WHERE MyColumn != 'somevalue'die NULL-Datensätze nicht zurückgegeben werden.
Jsumrall
88

NULL hat keinen Wert und kann daher nicht mit den Skalarwertoperatoren verglichen werden.

Mit anderen Worten, kein Wert kann jemals gleich (oder ungleich) NULL sein, da NULL keinen Wert hat.

Daher hat SQL spezielle IS NULL- und IS NOT NULL-Prädikate für den Umgang mit NULL.

Barry Brown
quelle
3
+1. Und im Gegensatz zur OP-Anweisung ist dies nicht "Microsoft SQL". Die Trinary-Logik ist im SQL-Standard definiert, und die MS hält sich an dieser Stelle an den Standard.
TomTom
6
Ich habe nicht vorgeschlagen, dass dies nur ein Microsoft-Verhalten ist. Ich habe lediglich angegeben, dass ich es auf Microsoft SQL Server beobachtet habe.
Maxim Gershkovich
13
Gibt es aus Interesse Situationen, in denen dieses (erwartete) Verhalten nützlich ist? Es scheint mir nur, dass es kontraintuitiv ist , 'a' != nullKEINEN Wert ( true/ 1) zurückzugeben, und mich von Zeit zu Zeit erwischt! Ich hätte gedacht, "ein Wert im Vergleich zu keinem Wert" wäre immer "nicht gleich", aber vielleicht bin das nur ich?!?
DarthPablo
1
Ich finde es interessant, dass die Leute NULL als " wertlos " beschreiben. Ähnlich wie zu sagen, dass die Zahl 1 "einen Wert hat", wenn es sich tatsächlich um einen Wert handelt. Aber NULL steht für Nicht-Wert ..
Systemaddict
Als manuelle Problemumgehung können Sie SELECT * FROM MyTable WHERE coalesce(MyColumn, 'x') <> 'x'normalerweise eine Konstante zuweisen, wenn es sich um einen NULL-Wert handelt, vorausgesetzt, Sie geben einen geeigneten Datentyp für den Sentinel-Wert x an (in diesem Fall eine Zeichenfolge / ein Zeichen). Dies ist die TSQL-Syntax, aber Oracle und andere Engines verfügen über ähnliche Funktionen.
Systemaddict
26

Beachten Sie, dass dieses Verhalten das Standardverhalten (ANSI) ist.

Wenn du:

 SET ANSI_NULLS OFF

http://msdn.microsoft.com/en-us/library/ms188048.aspx

Sie erhalten unterschiedliche Ergebnisse.

SET ANSI_NULLS OFF wird anscheinend in Zukunft weggehen ...

Cade Roux
quelle
8
+1 ... nicht früh genug. Wann kann ich "doppelte" NULL-Werte in einem Index erhalten? :(
Sie können doppelte NULL-Werte in einem SQL Server-Index erhalten, indem Sie eine WHERE-Klausel in einen gefilterten Index einfügen (z. B. create unique index UK_MyTable on MyTable (Column) where Column is not null): msdn.microsoft.com/en-us/library/cc280372.aspx
Anthony Mills
3
Hinweis aus den Dokumenten: Wenn SET ANSI_NULLSAUS ist, folgen die Vergleichsoperatoren Equals (=) und Not Equal To (<>) nicht dem ISO-Standard. Eine verwendete SELECT-Anweisung WHERE column_name = NULLgibt die Zeilen zurück, deren Spaltenname Nullwerte enthält. Eine verwendete SELECT-Anweisung WHERE column_name <> NULLgibt die Zeilen zurück, deren Spalte nicht null Werte enthält. Außerdem gibt eine verwendete SELECT-Anweisung WHERE column_name <> XYZ_valuealle Zeilen zurück, die nicht XYZ_value und nicht NULL sind. IMHO, diese letzte Aussage scheint ein wenig seltsam, da sie Nullen aus den Ergebnissen ausschließt!
DarthPablo
4
Wichtiger Hinweis aus dem msdn-Dokument : In einer zukünftigen Version von SQL Server [neuer als 2014] ist ANSI_NULLS immer eingeschaltet, und alle Anwendungen, die die Option explizit auf AUS setzen, erzeugen einen Fehler. Vermeiden Sie die Verwendung dieser Funktion in neuen Entwicklungsarbeiten und planen Sie, Anwendungen zu ändern, die diese Funktion derzeit verwenden.
Otiel
7

In SQL alles, was Sie mit NULLErgebnissen in UNBEKANNT auswerten / berechnen

Dies ist der Grund SELECT * FROM MyTable WHERE MyColumn != NULLoder SELECT * FROM MyTable WHERE MyColumn <> NULLgibt Ihnen 0 Ergebnisse.

Zur Überprüfung der NULLWerte wird die Funktion isNull bereitgestellt.

Darüber hinaus können Sie den ISOperator wie in der dritten Abfrage verwenden.

Hoffe das hilft.

Mahendra Liya
quelle
"In SQL führt alles, was Sie mit NULL auswerten / berechnen, zu 'NULL'" - falsch. Das Ergebnis, das Sie meinen, ist UNBEKANNT.
Tag, wenn
@MahendraLiya Die Funktion isNull wird nicht zur Überprüfung auf NULL bereitgestellt, sondern ersetzt " NULL durch den angegebenen Ersetzungswert ". Sie sollten IS NULL oder IS NOT NULL anstelle von ISNULL verwenden, was etwas anderes ist.
Umgekehrter Ingenieur
7

Der einzige Test für NULL ist IS NULL oder IS NOT NULL. Das Testen auf Gleichheit ist unsinnig, da man per Definition nicht weiß, was der Wert ist.

Hier ist ein Wikipedia-Artikel zu lesen:

https://en.wikipedia.org/wiki/Null_(SQL)

dkretz
quelle
6

Wir gebrauchen

SELECT * FROM MyTable WHERE ISNULL(MyColumn, ' ') = ' ';

um alle Zeilen zurückzugeben, in denen MyColumn NULL ist, oder alle Zeilen, in denen MyColumn eine leere Zeichenfolge ist. Für viele "Endbenutzer" ist das Problem NULL vs. leere Zeichenfolge eine Unterscheidung ohne Notwendigkeit und Verwirrung.

Jeff Mergler
quelle
5

Ich sehe nur nicht den funktionalen und nahtlosen Grund dafür, dass Nullen nicht mit anderen Werten oder anderen Nullen vergleichbar sind, weil wir sie klar vergleichen und sagen können, dass sie in unserem Kontext gleich sind oder nicht. Es ist lustig. Nur wegen einiger logischer Schlussfolgerungen und Beständigkeit müssen wir uns ständig damit beschäftigen. Es ist nicht funktional, macht es funktionaler und überlässt es Philosophen und Wissenschaftlern, zu schließen, ob es konsistent ist oder nicht, und enthält es "universelle Logik". :) Jemand könnte sagen, dass es an Indizes oder etwas anderem liegt. Ich bezweifle, dass diese Dinge nicht dazu gebracht werden konnten, Nullen wie Werte zu unterstützen. Es ist dasselbe wie zwei leere Gläser zu vergleichen, eines ist Weinglas und das andere ist Bierglas. Wir vergleichen nicht die Arten von Objekten, sondern die darin enthaltenen Werte, so wie Sie int und varchar mit null it vergleichen könnten. ' s noch einfacher, es ist nichts und was zwei Nichts gemeinsam haben, sie sind gleich, eindeutig vergleichbar von mir und allen anderen, die SQL schreiben, weil wir diese Logik ständig brechen, indem wir sie aufgrund einiger ANSI-Standards auf seltsame Weise vergleichen. Warum nicht Computerleistung verwenden, um dies für uns zu tun, und ich bezweifle, dass dies die Dinge verlangsamen würde, wenn alles, was damit zusammenhängt, in diesem Sinne konstruiert wird. "Es ist nicht null, es ist nichts", es ist nicht Apfel, es ist Apfel, komm schon ... Funktionell ist dein Freund und hier gibt es auch Logik. Am Ende kommt es nur auf die Funktionalität an, und die Verwendung von Nullen auf diese Weise bringt mehr oder weniger Funktionalität und Benutzerfreundlichkeit. Ist es nützlicher? weil wir diese Logik ständig brechen, indem wir sie aufgrund einiger ANSI-Standards auf seltsame Weise vergleichen. Warum nicht Computerleistung verwenden, um dies für uns zu tun, und ich bezweifle, dass dies die Dinge verlangsamen würde, wenn alles, was damit zusammenhängt, in diesem Sinne konstruiert wird. "Es ist nicht null, es ist nichts", es ist nicht Apfel, es ist Apfel, komm schon ... Funktionell ist dein Freund und hier gibt es auch Logik. Am Ende kommt es nur auf die Funktionalität an, und die Verwendung von Nullen auf diese Weise bringt mehr oder weniger Funktionalität und Benutzerfreundlichkeit. Ist es nützlicher? weil wir diese Logik ständig brechen, indem wir sie aufgrund einiger ANSI-Standards auf seltsame Weise vergleichen. Warum nicht Computerleistung verwenden, um dies für uns zu tun, und ich bezweifle, dass dies die Dinge verlangsamen würde, wenn alles, was damit zusammenhängt, in diesem Sinne konstruiert wird. "Es ist nicht null, es ist nichts", es ist nicht Apfel, es ist Apfel, komm schon ... Funktionell ist dein Freund und hier gibt es auch Logik. Am Ende kommt es nur auf die Funktionalität an, und die Verwendung von Nullen auf diese Weise bringt mehr oder weniger Funktionalität und Benutzerfreundlichkeit. Ist es nützlicher? s nicht Apfel, es ist Apfel, komm schon ... Funktionell ist dein Freund und hier gibt es auch Logik. Am Ende kommt es nur auf die Funktionalität an, und die Verwendung von Nullen auf diese Weise bringt mehr oder weniger Funktionalität und Benutzerfreundlichkeit. Ist es nützlicher? s nicht Apfel, es ist Apfel, komm schon ... Funktionell ist dein Freund und hier gibt es auch Logik. Am Ende kommt es nur auf die Funktionalität an, und die Verwendung von Nullen auf diese Weise bringt mehr oder weniger Funktionalität und Benutzerfreundlichkeit. Ist es nützlicher?

Betrachten Sie diesen Code:

SELECT CASE WHEN NOT (1 = null or (1 is null and null is null)) THEN 1 ELSE 0 end

Wie viele von Ihnen wissen, was dieser Code zurückgibt? Mit oder ohne NICHT gibt es 0 zurück. Für mich ist das nicht funktionsfähig und verwirrend. In c # ist alles so, wie es sein sollte, Vergleichsoperationen geben einen Wert zurück, logischerweise erzeugt auch dies einen Wert, denn wenn dies nicht der Fall ist, gibt es nichts zu vergleichen (außer nichts :)). Sie haben nur "gesagt": Alles im Vergleich zu null "gibt" 0 zurück und das schafft viele Problemumgehungen und Kopfschmerzen.

Dies ist der Code, der mich hierher gebracht hat:

where a != b OR (a is null and b IS not null) OR (a IS not null and b IS null)

Ich muss nur vergleichen, ob zwei Felder (in wo) unterschiedliche Werte haben, ich könnte Funktion verwenden, aber ...

Hrvoje Batrnek
quelle
4

NULL Mit den Vergleichsoperatoren kann kein Wert verglichen werden. NULL = NULL ist falsch. Null ist kein Wert. Der IS-Operator wurde speziell für NULL-Vergleiche entwickelt.

Vincent Ramdhanie
quelle
5
Ich habe es immer genossen, verwirrte Leute zu haben, wenn ich manchmal dort verwende, null = nullwo man es 1=0in einer Ad-hoc-Abfrage verwenden könnte. Und wenn sie sich beschweren, ändere ich es auf null != null:)
SWeko
8
"NULL = NULL ist falsch" Das ist nicht so. NULL = NULL wird als unbekannt und nicht als falsch ausgewertet .
Nvogel
@dportas das ist so, aber ich meinte, dass es in einer Bedingung nicht als wahr bewertet wird.
Vincent Ramdhanie
@ VincentRamdhanie weder als falsch; in der Tat, in Postgres wird es als NULL ausgewertet
Pere
2

Alte Frage, aber die folgende könnte einige Details bieten.

nullrepräsentiert keinen Wert oder einen unbekannten Wert. Es wird nicht angegeben, warum kein Wert vorhanden ist, was zu Mehrdeutigkeiten führen kann.

Angenommen, Sie führen eine Abfrage wie folgt aus:

SELECT *
FROM orders
WHERE delivered=ordered;

Das heißt, Sie suchen nach Zeilen, in denen Datum orderedund deliveredDatum identisch sind.

Was ist zu erwarten, wenn eine oder beide Spalten null sind?

Da mindestens eines der Daten unbekannt ist, können Sie nicht erwarten, dass die beiden Daten identisch sind. Dies ist auch dann der Fall, wenn beide Daten unbekannt sind: Wie können sie gleich sein, wenn wir nicht einmal wissen, was sie sind?

Aus diesem Grund muss jeder Ausdruck, der nullals Wert behandelt wird, fehlschlagen. In diesem Fall stimmt es nicht überein. Dies ist auch der Fall, wenn Sie Folgendes versuchen:

SELECT *
FROM orders
WHERE delivered<>ordered;

Wie können wir wieder sagen, dass zwei Werte nicht gleich sind, wenn wir nicht wissen, was sie sind?

SQL hat einen speziellen Test für fehlende Werte:

IS NULL

Insbesondere werden keine Werte verglichen , sondern fehlende Werte gesucht.

Was den !=Betreiber betrifft , so ist er meines Wissens in keinem der Standards enthalten, wird aber sehr weitestgehend unterstützt. Es wurde hinzugefügt, damit sich Programmierer aus einigen Sprachen wie zu Hause fühlen. Ehrlich gesagt, wenn ein Programmierer Schwierigkeiten hat, sich daran zu erinnern, welche Sprache er verwendet, hat er einen schlechten Start.

Manngo
quelle
Dies ist dieselbe "unsinnige" "Logik", die @Hove in seiner Antwort beschreibt. Die Wahrheit ist, dass in diesem Zusammenhang keine zusätzlichen Utensilien erforderlich sind. Es könnte leicht angenommen werden, dass wir, wenn wir etwas mit a vergleichen NULL, meinen, dass wir einen Wert mit "einen NULLWert haben" vergleichen, nicht den Wert mit "dem unbestimmten Wert, den die Unterlage NULLhat", aber dass wir es nicht wissen ", was wir natürlich nie erfahren werden. Das würde die Dinge wirklich erleichtern.
Pere
@Pere Ich würde nicht sagen, dass es streng „unsinnig“ ist, und ich bin mir nicht sicher, ob das Schreiben IS NULLviel schwieriger ist als das Schreiben = NULL. Ich denke, es wäre konsequenter, wenn WHERE columnA = columnBes die gleiche Interpretation wie hätte WHERE columnA = NULL, anstatt letzteres als Sonderfall zu behandeln. Denken Sie daran , dass NULList nicht ein Wert. In Programmiersprachen , wo es ist legitim zu testen , variable == nullist es, weil nulleine andere Bedeutung hat; es stellt nichts Unbekanntes dar, sondern ein absichtliches Zurücksetzen eines Wertes. Nicht so bei SQL.
Manngo
Deshalb setze ich es zwischen Anführungszeichen, @Mangoo;) (und auch "Logik"). Sei mir nicht böse; Ich habe über die ANSI "Argumentation" gesprochen, nicht über Ihre Erklärung. Ich stimme darin überein, dass zwischen IS NULLUND =NULLin Ihrem neuesten Beispiel kein Overhead besteht . Aber schauen Sie sich Hovers letzten an. Ich bin es leid, es immer wieder zu erleben und eine Menge unnötiger Dinge tun zu müssen? zusätzliche Überprüfung ...
Pere
1

Ich möchte diesen Code vorschlagen, den ich erstellt habe, um festzustellen, ob sich ein Wert ändert, ider neue Wert und dder alte (obwohl die Reihenfolge keine Rolle spielt). Im Übrigen ist eine Änderung von Wert zu Null oder umgekehrt eine Änderung, von Null zu Null jedoch nicht (natürlich ist eine Änderung von Wert zu einem anderen Wert eine Änderung, von Wert zu demselben jedoch nicht).

CREATE FUNCTION [dbo].[ufn_equal_with_nulls]
(
    @i sql_variant,
    @d sql_variant
)
RETURNS bit
AS
BEGIN
    DECLARE @in bit = 0, @dn bit = 0
    if @i is null set @in = 1
    if @d is null set @dn = 1

    if @in <> @dn
        return 0

    if @in = 1 and @dn = 1
        return 1

    if @in = 0 and @dn = 0 and @i = @d
        return 1

    return 0

END

Um diese Funktion zu verwenden, können Sie

declare @tmp table (a int, b int)
insert into @tmp values
(1,1),
(1,2),
(1,null),
(null,1),
(null,null)

---- in select ----
select *, [dbo].[ufn_equal_with_nulls](a,b) as [=] from @tmp

---- where equal ----
select *,'equal' as [Predicate] from @tmp where  [dbo].[ufn_equal_with_nulls](a,b) = 1

---- where not equal ----
select *,'not equal' as [Predicate] from @tmp where  [dbo].[ufn_equal_with_nulls](a,b) = 0

Die Ergebnisse sind:

---- in select ----
a   b   =
1   1   1
1   2   0
1   NULL    0
NULL    1   0
NULL    NULL    1

---- where equal ----
1   1   equal
NULL    NULL    equal

---- where not equal ----
1   2   not equal
1   NULL    not equal
NULL    1   not equal

Die Verwendung von sql_variant macht es für verschiedene Typen kompatibel

Yariv de Botton
quelle