2010-07-13 9 views
168

ho scritto una dichiarazione T-SQL simile come questo (l'originale aspetto diverso, ma voglio fare un esempio facile qui):T-SQL CASE Clausola: come specificare quando NULL

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

Questo Accordo non ha errori di sintassi ma la clausola case sceglie sempre la parte ELSE - anche se il cognome è nullo. Ma perché?

Quello che voglio fare è di unire first_name e cognome, ma se cognome è null l'intero nome diventa nulla:

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

Sapete dove è il problema?

risposta

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

@ Il suggerimento di Luther su COALESCE è migliore della mia risposta. È marginalmente meno efficiente, ma molto più elegante. –

+0

Gestirlo con qualcosa di simile può essere utile, o qualcosa del genere: COALESCE (last_name, '') La dichiarazione del caso, sebbene concisa, è meno manutenibile di COALESCE nelle query di grandi dimensioni. Alla fine, hai lo stesso risultato. Se è necessario ottimizzare, controllare i piani di esecuzione ma non ho notato molta differenza. –

+0

'COALESCE' fondamentalmente si traduce internamente in' CASE'. Il problema con CASE è che 'last_name' viene valutato due volte e può portare ad altri effetti collaterali - vedere questo eccellente [articolo] (http://sqlmag.com/t-sql/coalesce-vs-isnull). Per risolvere ciò che è stato chiesto, preferirei usare 'ISNULL ('' + last_name, '')' menzionato in [comment] (http://stackoverflow.com/questions/3237646/t-sql-case-clause-how -to-specificare-quando-null # comment3343348_3237704) sotto. – miroxlav

31

La QUANDO parte viene confrontato con ==, ma non si può davvero confrontare con NULL. Prova

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

invece o COALESCE:

COALESCE(' '+last_name,'') 

(' '+ last_name è NULL quando cognome è NULL, quindi dovrebbe tornare '' in questo caso)

+0

Ok, grazie per le informazioni con il == nella parte WHEN. Non lo sapevo. Con COALESCE funziona anche bene. Non ho pensato che ci siano così tante possibilità per farlo. – meni

11

Dato la query è possibile Anche fare questo:

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

Questo aggiunge uno spazio ridondante quando last_name è nullo, che è ciò che l'OP stava tentando di evitare. –

+5

Meglio usare 'ISNULL ('' + last_name, '')' per prevenire lo spazio ridondante. – Prutswonder

+0

Sì, l'ho realizzato dopo che l'ho postato. Ho pensato di lasciarlo da quando ha risolto la parte con cui stava avendo problemi. –

7

Il problema è che null non è considerato uguale a se stesso, quindi la clausola non corrisponde mai es.

è necessario controllare per nulla esplicitamente:

SELECT CASE WHEN last_name is NULL THEN first_name ELSE first_name + ' ' + last_name 
4

prova:

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

Questo si aggiunge lo spazio per il cognome, se è null, l'intero spazio + cognome va a NULL e ottieni solo un nome, altrimenti ottieni uno + + spazio + cognome.

questo funzionerà fino a quando l'impostazione di default per la concatenazione con stringhe nulle è impostato:

SET CONCAT_NULL_YIELDS_NULL ON 

questo non dovrebbe essere un problema in quanto la modalità OFF sta andando via nelle future versioni di SQL Server

6

Ci sono molte soluzioni ma nessuna copre il motivo per cui la dichiarazione originale non funziona.

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

Dopo il quando, v'è un controllo per l'uguaglianza, che dovrebbe essere vera o falsa.

Se una o entrambe le parti di un confronto sono nulle, il risultato del confronto sarà UNKNOWN, che viene trattato come falso in una struttura del caso. Vedi: https://www.xaprb.com/blog/2006/05/18/why-null-never-compares-false-to-anything-in-sql/

Per evitare questo, Coalesce è il modo migliore.

1
CASE 
    WHEN last_name IS null THEN '' 
    ELSE ' ' + last_name 
END 
+4

Er ... è esattamente la stessa della risposta accettata. –

0

Quando si ottiene frustrato cercando questo:

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

provare questo invece:

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

LEN(ISNULL(last_Name,'')) misura il numero di caratteri in quella colonna, che sarà zero se è vuoto o NULL, pertanto WHEN 0 THEN verrà valutato e su true e restituire il '' come previsto.

Spero che questa sia un'alternativa utile.

Ho incluso questo banco di prova per sql server 2008 e al di sopra:

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 
+2

Sei sicuro che funzioni?La maggior parte delle funzioni restituisce NULL quando viene dato un input NULL e i miei test confermano che è anche vero di LEN(), cioè LEN (NULL) restituisce NULL, non 0. –

+0

Pokechu22 è corretto, e questo è lo script corretto: CASE LEN (ISNULL (last_Name , '')) QUANDO 0 THEN '' ELSE '' + cognome END AS newlastName –

+0

Ho aggiornato in base ai commenti di Pokechu22. –

2

Il problema è che NULL non è considerata uguale a qualsiasi cosa, anche non a se stesso, ma la cosa strana è che è anche non uguale a uguale a se stesso.

Considerare le seguenti dichiarazioni (che è BTW illegale in SQL Server T-SQL ma è valida in My-SQL, tuttavia questo è ciò che ANSI definisce per null e può essere verificato anche in SQL Server utilizzando le istruzioni caso ecc.)

SELECT NULL = NULL -- Results in NULL

SELECT NULL <> NULL -- Results in NULL

è, come ci true false risposta alla domanda /, invece la risposta è anche nullo.

Questo ha molte implicazioni, ad esempio in

  1. dichiarazioni caso, in cui ogni valore nullo sarà sempre utilizzare la clausola ELSE se non si utilizza esplicitamente la condizione NULL QUANDO (NON la condizione WHEN NULL)
  2. concatenazione di stringhe, come
    SELECT a + NULL -- Results in NULL
  3. In una DOVE IN o WHERE NOT IN clausola, come se si desidera che i risultati corretti assicurarsi nella sottoquery correlata per filtrare eventuali valori nulli.

Si può ignorare questo comportamento in SQL Server specificando SET ANSI_NULLS OFF, tuttavia questo è NON raccomandato e non dovrebbe essere fatto in quanto può causare molti problemi, semplicemente perché la deviazione dello standard.

(Come nota laterale, in My-SQL v'è la possibilità di utilizzare un operatore speciale <=> di confronto nullo.)

In confronto, in linguaggi di programmazione generale nullo viene trattato è un valore normale ed è uguale a se stesso, tuttavia è il valore NAN che non è uguale a se stesso, ma almeno restituisce 'false' quando lo si confronta con se stesso (e quando si verifica che non sia uguale a diversi linguaggi di programmazione hanno implementazioni differenti).

Nota che nelle lingue di base (cioè VB ecc.) Non esiste una parola chiave 'null' e invece si utilizza la parola chiave 'Nothing', che non può essere utilizzata nel confronto diretto e invece è necessario utilizzare 'IS' come in SQL, tuttavia è di fatto uguale a se stesso (quando si usano confronti indiretti).

0

Jason catturato un errore, quindi questo funziona ...

Qualcuno può confermare le altre versioni di piattaforma?
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 

Oracle:

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

È possibile utilizzare la funzione IsNull

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

se una colonna è nullo si wo ULD ottenere un carattere vuoto

Compatibile con Microsoft SQL Server 2008+

0

Ho provato a lanciare in una stringa e la sperimentazione per una stringa di lunghezza zero e ha funzionato.

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

Utilizzare la funzione CONCAT disponibile in SQL Server 2012 in poi.

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

NULL non equivale a nulla. L'affermazione del caso dice fondamentalmente quando il valore = NULL ... non colpirà mai.
Esistono anche diverse stored procedure di sistema scritte in modo errato con la sintassi. Vedi sp_addpullsubscription_agent e sp_who2.
Vorrei sapere come comunicare a Microsoft di questi errori perché non sono in grado di modificare i proc memorizzati dal sistema.

Problemi correlati