T-SQL CASE-Klausel: So geben Sie WHEN NULL an

226

Ich habe eine ähnliche T-SQL-Anweisung geschrieben (die ursprüngliche sieht anders aus, aber ich möchte hier ein einfaches Beispiel geben):

SELECT first_name + 
    CASE last_name WHEN null THEN 'Max' ELSE 'Peter' END AS Name
FROM dbo.person

Diese Anweisung enthält keine Syntaxfehler, aber die case-Klausel wählt immer den ELSE-Teil aus - auch wenn der Nachname null ist. Aber wieso?

Was ich tun möchte, ist, Vorname und Nachname zu vereinen, aber wenn Nachname null ist, wird der gesamte Name null:

SELECT first_name +
   CASE last_name WHEN null THEN '' ELSE ' ' + last_name END AS Name 
FROM dbo.person

Wissen Sie, wo das Problem liegt?

Meni
quelle

Antworten:

368
CASE WHEN last_name IS NULL THEN '' ELSE ' '+last_name END
Marcelo Cantos
quelle
4
@ Luthers COALESCE-Vorschlag ist besser als meine Antwort. Es ist etwas weniger effizient, aber viel eleganter.
Marcelo Cantos
Die Behandlung mit so etwas kann nützlich sein oder so ähnlich: COALESCE (last_name, '') Die case-Anweisung ist zwar prägnant, aber in großen Abfragen weniger wartbar als COALESCE. Am Ende haben Sie das gleiche Ergebnis. Wenn Sie optimieren müssen, überprüfen Sie die Ausführungspläne, aber ich habe keinen großen Unterschied bemerkt.
Anthony Mason
1
COALESCEim Grunde intern übersetzt in CASE. Das Problem mit CASE ist, dass last_namees zweimal evaluiert wird und zu anderen Nebenwirkungen führen kann - siehe diesen ausgezeichneten Artikel . Um das zu lösen, was gefragt wurde, würde ich lieber mit dem ISNULL(' '+ last_name, '')im Kommentar unten erwähnten gehen .
Miroxlav
41

Der WHEN-Teil wird mit == verglichen, aber Sie können nicht wirklich mit NULL vergleichen. Versuchen

CASE WHEN last_name is NULL  THEN ... ELSE .. END

stattdessen oder COALESCE:

COALESCE(' '+last_name,'')

('' + Nachname ist NULL, wenn Nachname NULL ist, daher sollte in diesem Fall '' zurückgegeben werden)

Nordischer Mainframe
quelle
Okay, danke für die Informationen mit dem == im WHEN-Teil. Das wusste ich nicht. Mit COALESCE funktioniert es auch gut. Ich hätte nicht gedacht, dass es so viele Möglichkeiten gibt, das zu tun.
Meni
15

Es gibt viele Lösungen, aber keine deckt ab, warum die ursprüngliche Aussage nicht funktioniert.

CASE last_name WHEN null THEN '' ELSE ' '+last_name

Nach dem Wann gibt es eine Überprüfung auf Gleichheit, die wahr oder falsch sein sollte.

Wenn einer oder beide Teile eines Vergleichs null sind, ist das Ergebnis des Vergleichs UNBEKANNT, was in einer Fallstruktur wie falsch behandelt wird. Siehe: https://www.xaprb.com/blog/2006/05/18/why-null-never-compares-false-to-anything-in-sql/

Um dies zu vermeiden, ist Coalesce der beste Weg.

Kamahl
quelle
11

Mit Ihrer Anfrage können Sie auch Folgendes tun:

SELECT first_name + ' ' + ISNULL(last_name, '') AS Name FROM dbo.person
Ian Jacobs
quelle
2
Dies fügt einen redundanten Speicherplatz hinzu, wenn last_name null ist, was das OP zu vermeiden versuchte.
Marcelo Cantos
6
Besser verwenden ISNULL(' '+ last_name, ''), um den redundanten Speicherplatz zu verhindern.
Prutswonder
Yeah hat es realisiert, nachdem ich gepostet habe. Ich dachte, ich würde es verlassen, da es den Teil gelöst hat, mit dem er Probleme hatte.
Ian Jacobs
7

Das Problem ist, dass null nicht als gleichwertig angesehen wird, daher stimmt die Klausel nie überein.

Sie müssen explizit auf null prüfen:

SELECT CASE WHEN last_name is NULL THEN first_name ELSE first_name + ' ' + last_name
b0fh
quelle
5

Versuchen:

SELECT first_name + ISNULL(' '+last_name, '') AS Name FROM dbo.person

Dies fügt das Leerzeichen zum Nachnamen hinzu. Wenn es null ist, wird das gesamte Leerzeichen + Nachname auf NULL gesetzt und Sie erhalten nur einen Vornamen, andernfalls erhalten Sie ein erstes + Leerzeichen + Nachname.

Dies funktioniert so lange, wie die Standardeinstellung für die Verkettung mit Nullzeichenfolgen festgelegt ist:

SET CONCAT_NULL_YIELDS_NULL ON 

Dies sollte kein OFFProblem sein, da der Modus in zukünftigen Versionen von SQl Server nicht mehr verfügbar ist

KM.
quelle
4

Das Problem ist, dass NULL nicht als gleichwertig angesehen wird, auch nicht als sich selbst, aber der seltsame Teil ist, dass es auch nicht gleich sich selbst ist.

Berücksichtigen Sie die folgenden Anweisungen (die in SQL Server T-SQL übrigens illegal sind, in My-SQL jedoch gültig sind. Dies ist jedoch das, was ANSI für null definiert und auch in SQL Server mithilfe von case-Anweisungen usw. überprüft werden kann.)

SELECT NULL = NULL -- Results in NULL

SELECT NULL <> NULL -- Results in NULL

Es gibt also keine richtige / falsche Antwort auf die Frage, stattdessen ist die Antwort auch null.

Dies hat viele Auswirkungen, zum Beispiel in

  1. CASE-Anweisungen, bei denen jeder Nullwert immer die ELSE-Klausel verwendet, es sei denn, Sie verwenden explizit die WHEN IS NULL-Bedingung ( NICHT die WHEN NULLBedingung ).
  2. String-Verkettung, as
    SELECT a + NULL -- Results in NULL
  3. Stellen Sie in einer WHERE IN- oder WHERE NOT IN-Klausel sicher, dass in der korrelierten Unterabfrage alle Nullwerte herausgefiltert werden, als ob Sie korrekte Ergebnisse wünschen.

Sie können dieses Verhalten in SQL Server durch Angabe überschreiben. Dies SET ANSI_NULLS OFFwird jedoch NICHT empfohlen und sollte nicht durchgeführt werden, da dies viele Probleme verursachen kann, einfach aufgrund einer Abweichung vom Standard.

(Als Randnotiz gibt es in My-SQL die Option, einen speziellen Operator <=>für den Nullvergleich zu verwenden.)

Im Vergleich dazu wird in allgemeinen Programmiersprachen null als regulärer Wert behandelt und ist gleich sich selbst. Dies ist jedoch der NAN-Wert, der auch nicht gleich sich selbst ist, aber zumindest 'false' zurückgibt, wenn er mit sich selbst verglichen wird (und Wenn geprüft wird, ob verschiedene Programmiersprachen nicht gleich sind, haben sie unterschiedliche Implementierungen.

Beachten Sie jedoch, dass es in den Basissprachen (z. B. VB usw.) kein Schlüsselwort 'null' gibt und stattdessen das Schlüsselwort 'Nothing' verwendet wird, das nicht im direkten Vergleich verwendet werden kann. Stattdessen muss 'IS' wie in SQL verwendet werden. es ist jedoch in der Tat gleich sich selbst (wenn indirekte Vergleiche verwendet werden).

yoel halb
quelle
1
"Das Seltsame ist, dass es auch nicht gleich ist." => das ist nicht seltsam, wenn man bedenkt, dass null in SQL die Bedeutung 'unbekannt' hat. Etwas Unbekanntes ist höchstwahrscheinlich nicht dasselbe wie etwas anderes, das unbekannt ist.
JDC
1
CASE  
    WHEN last_name IS null THEN '' 
    ELSE ' ' + last_name 
END
Linda
quelle
1

Wenn Sie frustriert sind, versuchen Sie Folgendes:

CASE WHEN last_name IS NULL THEN '' ELSE ' '+last_name END

Versuchen Sie stattdessen dieses:

CASE LEN(ISNULL(last_Name,''))
WHEN 0 THEN '' 
ELSE ' ' + last_name
END AS newlastName

LEN(ISNULL(last_Name,''))Misst die Anzahl der Zeichen in dieser Spalte, die Null ist, unabhängig davon, ob sie leer oder NULL ist. Daher WHEN 0 THENwird sie als wahr ausgewertet und das '' wie erwartet zurückgegeben.

Ich hoffe das ist eine hilfreiche Alternative.

Ich habe diesen Testfall für SQL Server 2008 und höher aufgenommen:

DECLARE @last_Name varchar(50) = NULL

SELECT 
CASE LEN(ISNULL(@last_Name,''))
WHEN 0 THEN '' 
ELSE 'A ' + @last_name
END AS newlastName

SET @last_Name = 'LastName'

SELECT 
CASE LEN(ISNULL(@last_Name,''))
WHEN 0 THEN '' 
ELSE 'A ' + @last_name
END AS newlastName
Chef Slagle
quelle
2
Bist du sicher, dass das funktioniert? Die meisten Funktionen geben NULL zurück, wenn sie eine NULL-Eingabe erhalten, und meine Tests bestätigen, dass dies auch für LEN () gilt, dh LEN (NULL) gibt NULL zurück, nicht 0.
Jason Musgrove
Pokechu22 ist korrekt, und dies ist das korrigierte Skript: CASE LEN (ISNULL (last_Name, '')) WHEN 0 THEN '' ELSE '' + last_name END AS newlastName
Chef Slagle
0

Jason hat einen Fehler entdeckt, also funktioniert das ...

Kann jemand die anderen Plattformversionen bestätigen?
SQL Server:

SELECT
CASE LEN(ISNULL(last_name,'')) 
WHEN 0 THEN '' 
ELSE ' ' + last_name
END AS newlastName

MySQL:

SELECT
CASE LENGTH(IFNULL(last_name,'')) 
WHEN 0 THEN '' 
ELSE ' ' + last_name
END AS newlastName

Orakel:

SELECT
CASE LENGTH(NVL(last_name,'')) 
WHEN 0 THEN '' 
ELSE ' ' + last_name
END AS newlastName
Chef Slagle
quelle
0

Sie können die IsNull-Funktion verwenden

select 
    isnull(rtrim(ltrim([FirstName]))+' ','') +
    isnull(rtrim(ltrim([SecondName]))+' ','') +
    isnull(rtrim(ltrim([Surname]))+' ','') +
    isnull(rtrim(ltrim([SecondSurname])),'')
from TableDat

Wenn eine Spalte null ist, erhalten Sie ein leeres Zeichen

Kompatibel mit Microsoft SQL Server 2008+

Molem
quelle
0

Verwenden Sie die in SQL Server 2012 verfügbare CONCAT-Funktion.

SELECT CONCAT([FirstName], ' , ' , [LastName]) FROM YOURTABLE
TSQL
quelle
0

Ich habe versucht, eine Saite zu gießen und auf eine Saite mit der Länge Null zu testen, und es hat funktioniert.

CASE 
   WHEN LEN(CAST(field_value AS VARCHAR(MAX))) = 0 THEN 
       DO THIS
END AS field 
user2463829
quelle
0

NULL ist nichts gleich. Die case-Anweisung sagt im Grunde, wenn der Wert = NULL ist, wird er niemals getroffen.
Es gibt auch mehrere gespeicherte Systemprozeduren, die mit Ihrer Syntax falsch geschrieben wurden. Siehe sp_addpullsubscription_agent und sp_who2.
Ich wünschte, ich könnte Microsoft über diese Fehler informieren, da ich die im System gespeicherten Prozesse nicht ändern kann.

Joshua Walker
quelle