Operatore <>! = Non uguale su NULL


271

Qualcuno potrebbe spiegare il seguente comportamento in SQL?

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)

Risposte:


309

<>è SQL-92 standard; !=è il suo equivalente. Entrambi valutano i valori, il che NULLnon lo è - NULLè un segnaposto per dire che c'è l'assenza di un valore.

Ecco perché è possibile utilizzare IS NULL/ solo IS NOT NULLcome predicati per tali situazioni.

Questo comportamento non è specifico di SQL Server. Tutti i dialetti SQL conformi agli standard funzionano allo stesso modo.

Nota : per confrontare se il valore non è nullo , si utilizza IS NOT NULL, mentre per confrontare con valore non nullo , si utilizza <> 'YOUR_VALUE'. Non posso dire se il mio valore è uguale o meno uguale a NULL, ma posso dire se il mio valore è NULL o NOT NULL. Posso confrontare se il mio valore è diverso da NULL.


4
In realtà, credo <>che sia nelle specifiche 92 ma la maggior parte dei fornitori supporta !=e / o è inclusa in una specifica successiva come 99 o 03.
Thomas

2
@Thomas: Oracle non ha supportato !=fino a ~ 9i a quanto ho capito, il che ha portato molta sintassi ANSI-92. La mia convinzione è che MySQL sia simile, iniziando il supporto in 4.x.
OMG Pony

Ciò sembra suggerire che !=potrebbe essere stato incluso in una specifica successiva in alternativa a <>. Non ho le mani su nuove specifiche, quindi non posso dirlo con certezza.
Thomas,

2
Il risultato è WHERE MyColumn != NULLo WHERE MyColumn = NULLdeterministico? O in altre parole, è garantito che restituisca sempre 0 righe, non importa se MyColumnè nullable nel database o no?
Slauma,

11
Va anche notato che poiché !=valuta solo i valori, fare qualcosa del genere WHERE MyColumn != 'somevalue'non restituirà i record NULL.
jsumrall,

88

NULL non ha valore e quindi non può essere confrontato utilizzando gli operatori di valore scalare.

In altre parole, nessun valore può mai essere uguale a (o non uguale a) NULL perché NULL non ha valore.

Quindi, SQL ha speciali predicati IS NULL e IS NOT NULL per la gestione di NULL.


3
+1. E, contrariamente all'istruzione OP, questo non è "Microsoft SQL". La logica trinaria è definita nello standard SQL e MS in questo punto aderisce allo standard.
TomTom,

6
Non stavo suggerendo che questo è un comportamento unico di Microsoft. Stavo semplicemente affermando che l'ho osservato su Microsoft SQL Server.
Maxim Gershkovich,

13
Per interesse, ci sono situazioni in cui questo comportamento (previsto) è utile? Mi sembra solo che 'a' != nullNON restituire un valore ( true/ 1) sia contro intuitivo e mi sorprende di tanto in tanto! Avrei pensato che "un certo valore rispetto a nessun valore" sarebbe sempre "non uguale", ma forse sono solo io?!?
DarthPablo,

1
Penso che sia interessante che la gente descriva NULL come " privo di valore ". Simile, quindi, a dire che il numero 1 "ha un valore" quando in realtà è un valore. Ma NULL rappresenta non valore ..
systemaddict,

Come soluzione alternativa manuale, è possibile SELECT * FROM MyTable WHERE coalesce(MyColumn, 'x') <> 'x'assegnare comunemente una costante se è un valore NULL, purché si fornisca un tipo di dati appropriato per il valore sentinella x (in questo caso una stringa / carattere). Questa è la sintassi TSQL ma Oracle e altri motori hanno funzionalità simili.
systemaddict,

26

Si noti che questo comportamento è il comportamento predefinito (ANSI).

Se tu:

 SET ANSI_NULLS OFF

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

Otterrai risultati diversi.

SET ANSI_NULLS OFF apparentemente andrà via in futuro ...


8
+1 ... non abbastanza presto. Ora, quando posso ottenere NULL "duplicati" in un indice? :(

È possibile ottenere NULL duplicati in un indice di SQL Server aggiungendo una clausola WHERE in un indice filtrato (ad esempio create unique index UK_MyTable on MyTable (Column) where Column is not null): msdn.microsoft.com/en-us/library/cc280372.aspx
Anthony Mills,

3
Nota dai documenti: quando SET ANSI_NULLSè OFF, gli operatori di confronto Equals (=) e Not Equal To (<>) non seguono lo standard ISO. Un'istruzione SELECT che utilizza WHERE column_name = NULLrestituisce le righe con valori null in nome_colonna. WHERE column_name <> NULLUn'istruzione SELECT che utilizza restituisce le righe con valori non nulli nella colonna. Inoltre, un'istruzione SELECT che utilizza WHERE column_name <> XYZ_valuerestituisce tutte le righe che non sono XYZ_value e che non sono NULL. IMHO, quest'ultima affermazione sembra un po 'strana nella sua esclusione di valori nulli dai risultati!
DarthPablo,

4
Nota importante dal documento msdn : in una versione futura di SQL Server [più recente del 2014], ANSI_NULLS sarà sempre ON e tutte le applicazioni che impostano esplicitamente l'opzione su OFF genereranno un errore. Evita di utilizzare questa funzione nel nuovo lavoro di sviluppo e pianifica di modificare le applicazioni che attualmente utilizzano questa funzione.
Otiel,

7

In SQL, tutto ciò che valuti / calcoli con NULLrisultati in UNKNOWN

Ecco perché SELECT * FROM MyTable WHERE MyColumn != NULLo SELECT * FROM MyTable WHERE MyColumn <> NULLti dà 0 risultati.

Per fornire un controllo per i NULLvalori, viene fornita la funzione isNull.

Inoltre, è possibile utilizzare l' ISoperatore come utilizzato nella terza query.

Spero che questo ti aiuti.


"In SQL, tutto ciò che valuti / calcoli con NULL risulta in" NULL "" - errato. Il risultato che intendi è SCONOSCIUTO.
Onedayquando il

@MahendraLiya la funzione isNull non viene fornita per verificare la presenza di NULL , ma " Sostituisce NULL con il valore di sostituzione specificato. ". È necessario utilizzare IS NULL o IS NOT NULL anziché ISNULL, il che è diverso.
Ingegnere inverso


6

Noi usiamo

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

per restituire tutte le righe in cui MyColumn è NULL o tutte le righe in cui MyColumn è una stringa vuota. Per molti un "utente finale", il problema NULL vs. stringa vuota è una distinzione senza necessità e punto di confusione.


5

Semplicemente non vedo la ragione funzionale e senza soluzione di continuità per cui i null non siano paragonabili ad altri valori o altri null, perché possiamo chiaramente confrontarli e dire che sono uguali o meno nel nostro contesto. È divertente. Solo a causa di alcune conclusioni logiche e coerenza, dobbiamo preoccuparci costantemente di ciò. Non è funzionale, rendilo più funzionale e lascia che filosofi e scienziati concludano se è coerente o meno e contiene "logica universale". :) Qualcuno potrebbe dire che è a causa di indici o qualcos'altro, dubito che quelle cose non possano essere fatte per supportare valori null come i valori. È come confrontare due bicchieri vuoti, uno è un bicchiere di vite e l'altro è un bicchiere di birra, non stiamo confrontando i tipi di oggetti ma i valori che contengono, gli stessi che potresti confrontare int e varchar, con null ' È ancora più semplice, è nulla e ciò che due cose hanno in comune, sono le stesse, chiaramente paragonabili a me e a tutti gli altri che scrivono sql, perché rompiamo costantemente quella logica confrontandole in modi strani a causa di alcuni standard ANSI. Perché non usare il potere del computer per farlo per noi e dubito che rallenterebbe le cose se tutto ciò che è correlato fosse costruito pensando a quello. "Non è nulla, non è niente", non è Apple, è un apfel, dai ... Funzionalmente è tuo amico e qui c'è anche la logica. Alla fine l'unica cosa che conta è la funzionalità e l'uso di null in quel modo porta più o meno funzionalità e facilità d'uso. È più utile? perché rompiamo costantemente questa logica confrontandola in modi strani a causa di alcuni standard ANSI. Perché non usare il potere del computer per farlo per noi e dubito che rallenterebbe le cose se tutto ciò che è correlato fosse costruito pensando a quello. "Non è nulla, non è niente", non è Apple, è un apfel, dai ... Funzionalmente è tuo amico e qui c'è anche la logica. Alla fine l'unica cosa che conta è la funzionalità e l'uso di null in quel modo porta più o meno funzionalità e facilità d'uso. È più utile? perché rompiamo costantemente questa logica confrontandola in modi strani a causa di alcuni standard ANSI. Perché non usare il potere del computer per farlo per noi e dubito che rallenterebbe le cose se tutto ciò che è correlato fosse costruito pensando a quello. "Non è nulla, non è niente", non è Apple, è un apfel, dai ... Funzionalmente è tuo amico e qui c'è anche la logica. Alla fine l'unica cosa che conta è la funzionalità e l'uso di null in quel modo porta più o meno funzionalità e facilità d'uso. È più utile? s non è apple è apfel, dai ... Funzionalmente è tuo amico e qui c'è anche la logica. Alla fine l'unica cosa che conta è la funzionalità e l'uso di null in quel modo porta più o meno funzionalità e facilità d'uso. È più utile? s non è apple è apfel, dai ... Funzionalmente è tuo amico e qui c'è anche la logica. Alla fine l'unica cosa che conta è la funzionalità e l'uso di null in quel modo porta più o meno funzionalità e facilità d'uso. È più utile?

Considera questo codice:

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

Quanti di voi sanno cosa restituirà questo codice? Con o senza NOT restituisce 0. Per me questo non è funzionale ed è confuso. In c # è tutto come dovrebbe essere, le operazioni di confronto restituiscono valore, logicamente anche questo produce valore, perché in caso contrario non c'è nulla da confrontare (tranne. Niente :)). Hanno appena "detto": qualsiasi cosa rispetto a null "restituisce" 0 e questo crea molte soluzioni alternative e mal di testa.

Questo è il codice che mi ha portato qui:

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

Devo solo confrontare se due campi (in cui) hanno valori diversi, potrei usare la funzione, ma ...


4

NULL Non può essere confrontato con alcun valore utilizzando gli operatori di confronto. NULL = NULL è falso. Null non è un valore. L'operatore IS è appositamente progettato per gestire i confronti NULL.


5
Mi sono sempre piaciute le persone confuse quando a volte uso null = nulldove si potrebbe usare 1=0in qualche query ad hoc. E se si lamentano, lo cambio in null != null:)
SWeko,

8
"NULL = NULL è falso" Non è così. NULL = NULL viene valutato come sconosciuto e non falso.
nvogel,

@dportas è così, ma intendevo che in condizioni non verrà valutato come vero.
Vincent Ramdhanie,

@VincentRamdhanie né come falso; infatti, in postgres verrà valutato come NULL
Pere

2

Vecchia domanda, ma quanto segue potrebbe offrire qualche dettaglio in più.

nullnon rappresenta alcun valore o un valore sconosciuto. Non specifica perché non vi è alcun valore, il che può portare ad alcune ambiguità.

Supponiamo di eseguire una query come questa:

SELECT *
FROM orders
WHERE delivered=ordered;

cioè, stai cercando righe in cui le date orderede deliveredsono uguali.

Cosa ci si aspetta quando una o entrambe le colonne sono nulle?

Poiché almeno una delle date è sconosciuta, non puoi aspettarti di dire che le 2 date sono uguali. Questo è anche il caso in cui entrambe le date sono sconosciute: come possono essere uguali se non sappiamo nemmeno cosa siano?

Per questo motivo, qualsiasi espressione trattata nullcome un valore deve fallire. In questo caso, non corrisponderà. Questo è anche il caso se provi quanto segue:

SELECT *
FROM orders
WHERE delivered<>ordered;

Ancora una volta, come possiamo dire che due valori non sono gli stessi se non sappiamo cosa siano.

SQL ha un test specifico per i valori mancanti:

IS NULL

In particolare non sta confrontando i valori, ma piuttosto cerca valori mancanti .

Infine, per quanto riguarda l' !=operatore, per quanto ne so, in realtà non rientra in nessuno degli standard, ma è ampiamente supportato. È stato aggiunto per far sentire i programmatori di alcune lingue più a loro agio. Francamente, se un programmatore ha difficoltà a ricordare quale lingua stanno usando, stanno iniziando male.


Questa è la stessa "logica" "senza senso" descritta da @Hove nella sua risposta. La verità è che in questo contesto non è necessario quell'armamentario extra; si potrebbe facilmente supporre che quando stiamo confrontando qualcosa con un NULLintendiamo che stiamo confrontando un valore con 'avere un NULLvalore', non il valore con "il valore indeterminato che il sottostante NULLsta avendo? ma che non sappiamo ", che ovviamente non potremo mai sapere. Ciò faciliterebbe davvero le cose.
Pere,

@Per non direi che è strettamente "senza senso", e non sono sicuro che scrivere IS NULLsia molto più arduo che scrivere = NULL. Penso che sarebbe più coerente se WHERE columnA = columnBavesse la stessa interpretazione di WHERE columnA = NULL, piuttosto che considerare quest'ultimo come un caso speciale. Ricorda che nonNULL è un valore. Nei linguaggi di programmazione in cui è legittimo testarlo è perché ha un significato diverso; non rappresenta qualcosa di sconosciuto, ma un ripristino intenzionale di un valore. Non così con SQL. variable == nullnull
Manngo,

Ecco perché l'ho messo tra virgolette, @Mangoo;) (e anche "logica"). Non arrabbiarti con me; Stavo parlando del "ragionamento" ANSI, non della tua spiegazione. Sono d'accordo sul fatto che non ci sia sovraccarico tra IS NULLAND =NULLnel tuo ultimo esempio. Ma dai un'occhiata all'ultimo di Hover. Sono stanco di sperimentarlo ancora e ancora, dover fare un sacco di ¿inutili? controllo extra ...
Pere

1

Vorrei suggerire questo codice che ho creato per scoprire se c'è un cambiamento in un valore, iessendo il nuovo valore ed dessendo il vecchio (anche se l'ordine non ha importanza). Del resto, una modifica da valore a null o viceversa è una modifica, ma da null a null non lo è (ovviamente, dal valore a un altro valore è una modifica ma dal valore allo stesso non lo è).

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

Per usare questa funzione, puoi

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

I risultati sono:

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

L'uso di sql_variant lo rende compatibile per vari tipi


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.