Diferente <>! = Operador em NULL


271

Alguém poderia explicar o seguinte comportamento no 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)

Respostas:


309

<>é o padrão SQL-92; !=é o seu equivalente. Ambos avaliam valores, o que NULLnão é - NULLé um espaço reservado para dizer que há ausência de valor.

É por isso que você só pode usar IS NULL/ IS NOT NULLcomo predicado para essas situações.

Esse comportamento não é específico para o SQL Server. Todos os dialetos SQL compatíveis com os padrões funcionam da mesma maneira.

Nota : Para comparar se seu valor não é nulo , use IS NOT NULL, enquanto para comparar com valor não nulo , use <> 'YOUR_VALUE'. Não posso dizer se meu valor é igual ou não a NULL, mas posso dizer se meu valor é NULL ou NOT NULL. Posso comparar se meu valor é algo diferente de NULL.


4
Na verdade, eu acredito que é <>que está no 92 especificação, mas a maioria dos fornecedores de suporte !=e / ou está incluída em uma especificação mais tarde como 99 ou 03.
— Thomas

2
@ Thomas: O Oracle não suportou !=até ~ 9i, pelo que entendi, o que trouxe muita sintaxe ANSI-92. Minha crença é que o MySQL é semelhante, iniciando o suporte na versão 4.x.
— OMG Ponies

Isso parece sugerir que !=poderia ter sido incluído em uma especificação posterior como uma alternativa a <>. Não tenho minhas mãos em novas especificações, então não posso dizer com certeza.
— Thomas

2
É o resultado de WHERE MyColumn != NULLou WHERE MyColumn = NULLdeterminista? Ou, em outras palavras, é garantido o retorno sempre de 0 linhas, independentemente de MyColumnser nulo no banco de dados ou não?
— Slauma

11
Também deve ser observado que, porque !=apenas avalia valores, fazer algo como WHERE MyColumn != 'somevalue'não retornará os registros NULL.
— jsumrall

88

NULL não tem valor e, portanto, não pode ser comparado usando os operadores de valor escalar.

Em outras palavras, nenhum valor pode ser igual a (ou não) NULL porque NULL não tem valor.

Portanto, o SQL possui predicados especiais IS NULL e IS NOT NULL para lidar com NULL.


3
+1. E, ao contrário da instrução OP, isso não é "Microsoft SQL". A lógica trinária é definida no SQL Standard e o MS, neste ponto, adere ao padrão.
— TomTom

6
Eu não estava sugerindo que este é um comportamento exclusivo da Microsoft. Eu estava simplesmente afirmando que o observei no Microsoft SQL Server.
— precisa saber é o seguinte

13
Fora de interesse, existem situações em que esse comportamento (esperado) é útil? Parece-me que 'a' != nullNÃO devolver um valor ( true/ 1) é contra-intuitivo e me pega de vez em quando! Eu teria pensado que "algum valor comparado a nenhum valor" sempre seria "não igual", mas talvez seja apenas eu?!?
— DarthPablo

1
Eu acho interessante que as pessoas descrevam NULL como ' sem valor '. Semelhante, então, dizer que o número 1 'tem um valor' quando na verdade é um valor. Mas NULL representa não-valor .. #
— systemmaddict 27/06

Como solução alternativa manual, você pode SELECT * FROM MyTable WHERE coalesce(MyColumn, 'x') <> 'x'atribuir uma constante se for um valor NULL, desde que você forneça um tipo de dados apropriado para o valor sentinela x (nesse caso, uma string / char). Essa é a sintaxe do TSQL, mas o Oracle e outros mecanismos têm recursos semelhantes.
— systemaddict

26

Observe que esse comportamento é o comportamento padrão (ANSI).

Se vocês:

 SET ANSI_NULLS OFF

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

Você obterá resultados diferentes.

SET ANSI_NULLS OFF aparentemente vai desaparecer no futuro ...


8
+1 ... não em breve. Agora, quando posso obter NULLs "duplicados" em um índice? :(

Você pode obter nulos duplicados em um índice SQL Server, adicionando uma cláusula WHERE em um índice filtrado (por exemplo 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 dos documentos: Quando SET ANSI_NULLSestá DESATIVADO, os operadores de comparação Igual a (=) e Diferente de (<>) não seguem o padrão ISO. Uma instrução SELECT que usa WHERE column_name = NULLretorna as linhas que possuem valores nulos em column_name. Uma instrução SELECT que usa WHERE column_name <> NULLretorna as linhas que possuem valores não nulos na coluna. Além disso, uma instrução SELECT que usa WHERE column_name <> XYZ_valueretorna todas as linhas que não são XYZ_value e que não são NULL. IMHO, esta última afirmação parece um pouco estranha na exclusão de valores nulos dos resultados!
— DarthPablo

4
Nota importante do msdn doc : Em uma versão futura do SQL Server [mais recente que 2014], o ANSI_NULLS sempre estará LIGADO e qualquer aplicativo que defina explicitamente a opção como DESLIGADO gerará um erro. Evite usar esse recurso em novos trabalhos de desenvolvimento e planeje modificar os aplicativos que atualmente usam esse recurso.
— Otiel

7

No SQL, qualquer coisa que você avalie / calcule com NULLresultados em DESCONHECIDO

É por isso que SELECT * FROM MyTable WHERE MyColumn != NULLou SELECT * FROM MyTable WHERE MyColumn <> NULLfornece 0 resultados.

Para fornecer uma verificação de NULLvalores, a função isNull é fornecida.

Além disso, você pode usar o ISoperador como usou na terceira consulta.

Espero que isto ajude.


"No SQL, qualquer coisa que você avalie / calcule com resultados NULL em 'NULL'" - incorreto. O resultado que você quer dizer é DESCONHECIDO.
— precisa saber é o seguinte

@MahendraLiya, a função isNull não é fornecida para verificar NULLS, mas " Substitui NULL pelo valor de substituição especificado ". Você deve usar IS NULL ou IS NOT NULL em vez de ISNULL, o que é uma coisa diferente.
— Reversed Engineer


6

Nós usamos

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

para retornar todas as linhas em que MyColumn é NULL ou todas as linhas em que MyColumn é uma sequência vazia. Para muitos "usuários finais", o problema de seqüência de caracteres NULL vs. vazio é uma distinção sem necessidade e ponto de confusão.


5

Eu simplesmente não vejo a razão funcional e perfeita para que os nulos não sejam comparáveis ​​a outros valores ou outros nulos, porque podemos compará-lo claramente e dizer que eles são iguais ou não em nosso contexto. É engraçado. Só por causa de algumas conclusões lógicas e consistência, precisamos nos preocupar constantemente com isso. Não é funcional, torne-o mais funcional e deixe que filósofos e cientistas concluam se é consistente ou não e mantém a "lógica universal". :) Alguém pode dizer que é por causa de índices ou qualquer outra coisa, duvido que essas coisas não pudessem ser feitas para suportar nulos iguais aos valores. É o mesmo que comparar dois copos vazios, um é copo de vinho e outro é copo de cerveja; não estamos comparando os tipos de objetos, mas os valores que eles contêm, o mesmo que você pode comparar int e varchar, com nulo ' é ainda mais fácil, não é nada e o que dois nada têm em comum, eles são os mesmos, claramente comparáveis ​​por mim e por todos os outros que escrevem sql, porque estamos constantemente quebrando essa lógica, comparando-os de maneiras estranhas por causa de alguns padrões ANSI. Por que não usar a energia do computador para fazer isso por nós e duvido que isso acelere as coisas se tudo relacionado for construído com isso em mente. "Não é nulo, não é nada", não é maçã, é apfel, vamos lá ... Funcionalmente é seu amigo e também há lógica aqui. No final, a única coisa que importa é a funcionalidade e o uso de nulos dessa maneira traz mais ou menos funcionalidade e facilidade de uso. É mais útil? porque estamos constantemente quebrando essa lógica, comparando-os de maneiras estranhas por causa de alguns padrões ANSI. Por que não usar a energia do computador para fazer isso por nós e duvido que isso acelere as coisas se tudo relacionado for construído com isso em mente. "Não é nulo, não é nada", não é maçã, é apfel, vamos lá ... Funcionalmente é seu amigo e também há lógica aqui. No final, a única coisa que importa é a funcionalidade e o uso de nulos dessa maneira traz mais ou menos funcionalidade e facilidade de uso. É mais útil? porque estamos constantemente quebrando essa lógica, comparando-os de maneiras estranhas por causa de alguns padrões ANSI. Por que não usar a energia do computador para fazer isso por nós e duvido que isso acelere as coisas se tudo relacionado for construído com isso em mente. "Não é nulo, não é nada", não é maçã, é apfel, vamos lá ... Funcionalmente é seu amigo e também há lógica aqui. No final, a única coisa que importa é a funcionalidade e o uso de nulos dessa maneira traz mais ou menos funcionalidade e facilidade de uso. É mais útil? s não maçã é apfel, vamos lá ... Funcionalmente é seu amigo e também há lógica aqui. No final, a única coisa que importa é a funcionalidade e o uso de nulos dessa maneira traz mais ou menos funcionalidade e facilidade de uso. É mais útil? s não maçã é apfel, vamos lá ... Funcionalmente é seu amigo e também há lógica aqui. No final, a única coisa que importa é a funcionalidade e o uso de nulos dessa maneira traz mais ou menos funcionalidade e facilidade de uso. É mais útil?

Considere este código:

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

Quantos de vocês sabem o que esse código retornará? Com ou sem NÃO, retorna 0. Para mim, isso não é funcional e é confuso. No c #, tudo é como deveria ser, as operações de comparação retornam valor, logicamente isso também produz valor, porque, se isso não acontecesse, não havia nada para comparar (exceto nada :):). Eles apenas "disseram": qualquer coisa comparada com "retornos" nulos 0 e que cria muitas soluções alternativas e dores de cabeça.

Este é o código que me trouxe aqui:

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

Eu só preciso comparar se dois campos (em onde) têm valores diferentes, eu poderia usar a função, mas ...


4

NULL Não pode ser comparado a nenhum valor usando os operadores de comparação. NULL = NULL é falso. Nulo não é um valor. O operador IS é especialmente projetado para lidar com comparações NULL.


5
Eu sempre gostei de pessoas confusas quando às vezes uso null = nullonde alguém pode usar 1=0em alguma consulta ad-hoc. E se eles se queixam, eu mudar para null != null:)
— Sweko

8
"NULL = NULL é falso" Isso não é verdade. NULL = NULL é avaliado como desconhecido e não falso.
— Nvogel

@portas isso é verdade, mas eu quis dizer que, de forma condicional, não será avaliada como verdadeira.
— Vincent Ramdhanie

@VincentRamdhanie nem como falso; de fato, no postgres ele será avaliado como NULL
— Pere

2

Pergunta antiga, mas o seguinte pode oferecer mais detalhes.

nullrepresenta nenhum valor ou um valor desconhecido. Não especifica por que não há valor, o que pode levar a alguma ambiguidade.

Suponha que você execute uma consulta como esta:

SELECT *
FROM orders
WHERE delivered=ordered;

isto é, você está procurando linhas nas quais as datas orderede deliveredsão iguais.

O que é esperado quando uma ou ambas as colunas são nulas?

Como pelo menos uma das datas é desconhecida, você não pode esperar dizer que as duas datas são iguais. Este também é o caso quando as duas datas são desconhecidas: como podem ser as mesmas se nem sabemos o que são?

Por esse motivo, qualquer expressão que trate nullcomo um valor deve falhar. Nesse caso, não corresponderá. Este também é o caso se você tentar o seguinte:

SELECT *
FROM orders
WHERE delivered<>ordered;

Novamente, como podemos dizer que dois valores não são os mesmos se não sabemos o que são.

SQL tem um teste específico para valores ausentes:

IS NULL

Especificamente, não está comparando valores, mas procura valores ausentes .

Finalmente, no que diz respeito ao !=operador, tanto quanto sei, ele não está de fato em nenhuma das normas, mas é amplamente suportado. Foi adicionado para fazer com que programadores de alguns idiomas se sintam mais à vontade. Francamente, se um programador tem dificuldade em lembrar qual idioma está usando, ele começa mal.


Essa é a mesma lógica "absurda" que o @Hove está descrevendo em sua resposta. A verdade é que, neste contexto, não há necessidade de parafernália extra; pode-se facilmente assumir que, quando comparamos algo a um, NULLqueremos dizer que estamos comparando um valor a 'ter um NULLvalor', não o valor ao "valor indeterminado que o subjacente NULLestá tendo? mas que não sabemos ", que obviamente não poderemos saber. Isso realmente facilitaria as coisas.
— Pere

@Pere Eu não diria que é estritamente "sem sentido", e não tenho certeza de que escrever IS NULLseja muito mais árduo do que escrever = NULL. Eu acho que seria mais consistente se WHERE columnA = columnBtivesse a mesma interpretação que WHERE columnA = NULL, em vez de tratar a última como um caso especial. Lembre-se que nãoNULL é um valor. Nas linguagens de programação em que é legítimo testá- lo, é porque tem um significado diferente; não representa algo desconhecido, mas uma redefinição deliberada de um valor. Não é assim com o SQL. variable == nullnull
— Manngo 12/04/19

É por isso que coloquei entre aspas, @Mangoo;) (e também "lógica"). Não fique bravo comigo; Eu estava falando sobre o "raciocínio" ANSI, não sobre sua explicação. Concordo que não há sobrecarga entre IS NULLAND =NULLno seu exemplo mais recente. Mas dê uma olhada no último de Hover. Estou cansado de experimentar isso de novo e de novo, tendo que fazer muitas coisas desnecessárias? verificação extra ...
— Pere

1

Gostaria de sugerir esse código que fiz para descobrir se há uma alteração em um valor, isendo o novo valor e do antigo (embora a ordem não importe). Nesse caso, uma mudança de valor para nulo ou vice-versa é uma mudança, mas de nulo para nulo não é (é claro, de valor para outro valor é uma mudança, mas de valor para o mesmo não é).

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

Para usar esta função, você pode

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

Os resultados são:

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

O uso de sql_variant o torna compatível com vários tipos


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.