Por que NULL = NULL é avaliado como falso no SQL server

146

No SQL server, se você tiver nullParam=NULLuma cláusula where, ela sempre será avaliada como falsa. Isso é contra-intuitivo e me causou muitos erros. Entendo que as palavras IS NULL- IS NOT NULLchave e são a maneira correta de fazer isso. Mas por que o SQL Server se comporta dessa maneira?

Byron Whitlock
fonte
166
Eu não tenho uma irmã, e nem meu amigo. Se "NULL = NULL", temos uma irmã em comum e, portanto, estamos relacionados! :)
Matt Hamilton
11
Há uma longa controvérsia sobre SQL NULLs (consulte, por exemplo: en.wikipedia.org/wiki/Null_%28SQL%29#Controversy e firstsql.com/inulls.htm ). O ponto específico aqui é que igualdade é um conceito matemático estabelecido há muito tempo e o SQL a viola - a igualdade é reflexiva: para cada x, x = x. Isso deve ser sempre verdadeiro, caso contrário, alguém está introduzindo uma interpretação da igualdade que não é padrão e a confusão é o resultado óbvio.
MaD70
14
Não viola a matemática. Estou pensando em dois números. Eu não vou lhe dizer o que são. Então agora você me diz, eles são iguais?
Tom H
10
@ Matt, eu não concordo com a sua analogia. NULL = NULL não significaria que você tem uma irmã em comum, significaria que os dois não têm uma irmã.
reustmd
5
@ manu08 Não, a implementação atual (que NULL nunca é igual a NULL) significa que nós dois não temos uma irmã, e esse foi o meu ponto.
Matt Hamilton

Respostas:

205

Pense no nulo como "desconhecido" nesse caso (ou "não existe"). Em qualquer um desses casos, você não pode dizer que eles são iguais, porque você não conhece o valor de nenhum deles. Portanto, null = null avalia como não verdadeiro (falso ou nulo, dependendo do seu sistema), porque você não conhece os valores para dizer que eles são iguais. Esse comportamento é definido no padrão ANSI SQL-92.

EDIT: Isso depende da sua configuração ansi_nulls . se você tiver ANSI_NULLS desativado, isso será avaliado como verdadeiro. Execute o seguinte código para um exemplo ...

set ansi_nulls off

if null = null
    print 'true'
else
    print 'false'


set ansi_nulls ON

if null = null
    print 'true'
else
    print 'false'
Scott Ivey
fonte
11
x = x só é válido quando x é um valor conhecido . NULL é uma representação textual de um valor desconhecido . Se você tem dois valores desconhecidos, não pode afirmar conclusivamente nada sobre a igualdade deles. Eu acredito que isso também se manteve por alguns séculos.
Dewayne Christensen 03/12/2009
4
Como é dezembro, vamos usar um exemplo sazonal. Eu tenho dois presentes embaixo da árvore. Agora, você me diz se eu tenho duas da mesma coisa ou não.
Dewayne Christensen 04/12/2009
5
O SQL NULL não é diferente do NaN de ponto flutuante IEEE, onde você também tem (NaN == NaN) == false && (NaN != Nan) == false && (NaN < NaN) == false && ...- porque, bem, se não é um número, você simplesmente não pode dizer muito sobre isso; é algo desconhecido. O conceito é sólido, mesmo que não seja intuitivo para pessoas que nunca o viram antes.
Pavel Minaev 04/12/2009
8
Não há violação da reflexividade aqui, porque NULL não é um membro do conjunto de valores (domínio, em termos relacionais). NULL não é um valor . É um espaço reservado para o valor que é desconhecido.
Pavel Minaev 04/12/2009
9
Em outras palavras, todas NULLas expressões SQL podem ser tratadas como uma variável matemática distinta . Portanto, uma expressão NULL = NULLdeve ser tratada como x = y, onde xe ysão variáveis ​​não acopladas. Agora, se alguém lhe perguntar, qual é o valor x = y? A única resposta razoável é "alguns z". Então nós temos (x = y) = z- ou, transcrevendo de volta para o SQL (NULL = NULL) = NULL,.
Pavel Minaev 04/12/2009
130

Quantos anos Frank tem? Eu não sei (nulo).

Quantos anos tem Shirley? Eu não sei (nulo).

Frank e Shirley têm a mesma idade?

A resposta correta deve ser "não sei" (nulo), não "não", como Frank e Shirley podem ter a mesma idade, simplesmente não sabemos.

Neil McGuigan
fonte
4
Eu discordo que nulo significa "desconhecido". O que realmente significa é "sem dados". Isso pode ser usado para representar o caso em que a informação não é conhecida, mas na verdade é mais provável que seja usada para indicar que algo não existe. Para continuar seu exemplo: Qual é o nome do meio de Frank? Ele não tem um (nulo). Qual é o nome do meio de Shirley? Ela não tem um (nulo). Frank e Shirley têm o mesmo nome do meio? Sim? Não? Não sabe? Posso ver um argumento para "não" e posso ver um argumento para "não sei", mas não há argumento real para "sim", a menos que você esteja sendo excessivamente literal.
Richiban
2
@richiban Eu discordo. A falta de existência de um meio de linha 'dados'
Neil McGuigan
1
@NeilMcGuigan Isso é verdade se os dados tiverem sua própria tabela, mas e os dados representados em uma coluna? Você não usaria 'null' para representar o fato de que os dados não existem? 'Desconhecido' é uma razão muito específica para os dados estarem ausentes.
Richiban
3
Mas null = nullproduz FALSE, não NULL.
slartidan
1
@slartidan eu concordo com você, no entanto, que é incorreta
Neil McGuigan
28

Espero esclarecer aqui minha posição.

Essa NULL = NULLavaliação FALSEestá errada. Hacker e Mister responderam corretamente NULL. Aqui está o porquê. Dewayne Christensen escreveu para mim, em um comentário para Scott Ivey :

Como é dezembro, vamos usar um exemplo sazonal. Eu tenho dois presentes embaixo da árvore. Agora, você me diz se eu tenho duas da mesma coisa ou não.

Eles podem ser diferentes ou iguais, você não sabe até que um abra os dois presentes. Quem sabe? Você convidou duas pessoas que não se conhecem e ambos têm feito para você o mesmo dom - raro, mas não impossível § .

Portanto, a pergunta: esses dois DESCONHECIDOS apresentam o mesmo (igual, =)? A resposta correta é: DESCONHECIDO (ie NULL).

Este exemplo teve como objetivo demonstrar que ".. ( falseou null, dependendo do seu sistema) .." é uma resposta correta - não é, apenas NULL é correta em 3VL (ou é aceitável que você aceite um sistema que fornece respostas erradas? )

Uma resposta correta para esta pergunta deve enfatizar esses dois pontos:

  • a lógica de três valores (3VL) é contra-intuitiva (consulte inúmeras outras perguntas sobre esse assunto no Stackoverflow e em outro fórum para garantir);
  • Os DBMSs baseados em SQL geralmente não respeitam até 3VL, mas às vezes dão respostas erradas (como afirma o pôster original, o SQL Server nesse caso).

Por isso, reitero: o SQL não ajuda em nada a interpretar a propriedade reflexiva da igualdade, que afirma que:

for any x, x = x §§ (em inglês simples: seja qual for o universo do discurso, uma "coisa" é sempre igual a si mesma ).

.. num 3VL ( TRUE, FALSE, NULL). A expectativa das pessoas estaria de acordo com 2VL ( TRUE, FALSEque mesmo em SQL é válida para todos os outros valores), ou seja, x = x sempre avaliar a TRUE , para qualquer valor possível de x - sem exceções.

Observe também que os NULLs são " não valores " válidos (como seus apologistas pretendem que sejam) que podem ser atribuídos como valores de atributo (??) como parte das variáveis ​​de relação. Portanto, eles são valores aceitáveis ​​de todos os tipos (domínio), não apenas do tipo de expressões lógicas.

E esse foi o meu argumento : NULLcomo valor, é uma "besta estranha". Sem eufemismo, prefiro dizer: bobagem .

Eu acho que essa formulação é muito mais clara e menos discutível - desculpe pela minha baixa proficiência em inglês.

Este é apenas um dos problemas dos NULLs. Melhor evitá-los completamente, quando possível.

§ estamos preocupados com os valores aqui; portanto, o fato de os dois presentes serem sempre dois objetos físicos diferentes não é uma objeção válida; se você não está convencido, desculpe, não é este o lugar para explicar a diferença entre semântica de valor e de "objeto" (a Álgebra Relacional tem semântica de valor desde o início - consulte o princípio da informação do Codd; acho que alguns implementadores do SQL DBMS não nem se importa com uma semântica comum).

§§ que eu saiba, esse é um axioma aceito (de uma forma ou de outra, mas sempre interpretado em uma 2VL) desde a antiguidade e exatamente por ser tão intuitivo. 3VLs (é uma família de lógicas na realidade) é um desenvolvimento muito mais recente (mas não tenho certeza de quando foi desenvolvido).

Nota lateral: se alguém introduzir os tipos Bottom , Unit e Option como tentativas de justificar SQL NULLs, ficarei convencido apenas após um exame bastante detalhado que mostrará como as implementações SQL com NULLs têm um sistema de tipo de som e esclarecerá, finalmente, o que realmente são NULLs (esses "valores-não-valores-iguais").


A seguir, citarei alguns autores. Qualquer erro ou omissão é provavelmente meu e não dos autores originais.

Joe Celko em SQL NULLs

Eu vejo Joe Celko frequentemente citado neste fórum. Aparentemente, ele é um autor muito respeitado aqui. Então, eu disse a mim mesmo: "o que ele escreveu sobre SQL NULLs? Como ele explica vários problemas com NULLs?". Um amigo meu tem uma versão eletrônica do SQL for smarties de Joe Celko: programação SQL avançada, 3ª edição . Vamos ver.

Primeiro, o sumário. O que mais me impressiona é o número de vezes que NULL é mencionado e nos mais variados contextos:

3.4 Aritmética e NULLs 109
3.5 Convertendo valores de e para NULL 110
3.5.1 Função NULLIF () 110
6 NULLs: dados ausentes no SQL 185
6.4 Comparando NULLs 190
6.5 NULLs e lógica 190
6.5.1 NULLS e Predicados do Subquery 191
6.5.2 Padrão Soluções SQL 193
6.6 Matemática e NULLs 193
6,7 Funções e NULLs 193
6,8 NULLs e idiomas do host 194
6,9 Recomendações de design para NULLs 195
6.9.1 Evitar NULLs dos programas host 197
6.10 Uma observação sobre vários valores NULL 198
10.1 Predicado IS NULL 241
10.1. 1 Fontes de NULLs 242
...

e assim por diante. Soa "um caso especial desagradável" para mim.

Vou abordar alguns desses casos com trechos deste livro, tentando me limitar ao essencial, por razões de direitos autorais. Acho que essas citações se enquadram na doutrina do "uso justo" e podem até estimular a compra do livro - por isso espero que ninguém reclame (caso contrário, precisarei excluir a maior parte, se não todas). Além disso, evitarei relatar trechos de código pelo mesmo motivo. Me desculpe por isso. Compre o livro para ler sobre o raciocínio com dados.

Números de página entre parênteses a seguir.

Restrição NÃO NULL (11)

A restrição de coluna mais importante é o NOT NULL, que proíbe o uso de NULLs em uma coluna. Use essa restrição rotineiramente e remova-a apenas quando tiver um bom motivo. Isso ajudará a evitar as complicações dos valores NULL quando você fizer consultas nos dados.

Não é um valor ; é um marcador que ocupa um lugar onde um valor pode ir.

Mais uma vez, esse absurdo de "valor, mas não exatamente um valor". O resto parece bastante sensato para mim.

(12)

Em resumo, os NULLs causam muitos recursos irregulares no SQL, os quais discutiremos mais adiante. Sua melhor aposta é apenas para memorizar as situações e as regras para NULLs quando você não puder evitá-las.

A propósito de SQL, NULLs e infinito:

(104) CAPÍTULO 3: DADOS NUMÉRICOS EM SQL

O SQL não aceitou o modelo IEEE para matemática por vários motivos.

...

Se as regras IEEE para matemática fossem permitidas no SQL, precisaríamos de regras de conversão de tipo para infinito e uma maneira de representar um valor numérico exato infinito após a conversão. As pessoas têm problemas suficientes com NULLs, então não vamos lá.

Implementações de SQL indecisas sobre o que NULL realmente significa em contextos específicos:

3.6.2 Funções exponenciais (116)

O problema é que os logaritmos são indefinidos quando (x <= 0). Algumas implementações SQL retornam uma mensagem de erro, outras retornam um NULL e DB2 / 400; a versão 3, liberação 1, retornou * NEGINF (abreviação de "infinito negativo") como resultado.

Joe Celko citando David McGoveran e CJ Date:

6 NULLs: dados ausentes no SQL (185)

No livro A Guide to Sybase e SQL Server , David McGoveran e CJ Date disseram: “A opinião deste escritor é que os NULLs, pelo menos como atualmente definidos e implementados no SQL, são muito mais problemáticos do que valem a pena e devem ser evitados; eles exibem um comportamento muito estranho e inconsistente e podem ser uma rica fonte de erro e confusão. (Observe que esses comentários e críticas se aplicam a qualquer sistema que suporte NULLs no estilo SQL, não apenas ao SQL Server especificamente.) ”

Nulos como um vício em drogas :

(186/187)

No restante deste livro, pedirei que você não os use , o que pode parecer contraditório, mas não é. Pense em um NULL como uma droga; use-o corretamente e funcione para você, mas abuse e pode estragar tudo. Sua melhor política é evitar NULLs quando possível e usá-los adequadamente quando necessário.

Minha objeção exclusiva aqui é "usá-los adequadamente", que interage mal com comportamentos de implementação específicos.

6.5.1 NULLS em predicados de subconsulta (191/192)

As pessoas esquecem que uma subconsulta geralmente oculta uma comparação com um NULL. Considere estas duas tabelas:

...

O resultado estará vazio. Isso é contra - intuitivo , mas correto.

(separador)

6.5.2 Soluções SQL padrão (193)

O SQL-92 resolveu alguns dos problemas de 3VL (lógica de três valores) adicionando um novo predicado do formulário:

<condição de pesquisa> É [NÃO] VERDADEIRO | FALSO DESCONHECIDO

Mas UNKNOWN é uma fonte de problemas em si, de modo que CJ Date, em seu livro citado abaixo, é recomendado no capítulo 4.5. Evitando nulos no SQL :

  • Não use a palavra-chave DESCONHECIDA em nenhum contexto.

Leia "ASIDE" em DESCONHECIDO, também linkado abaixo.

6.8 NULLs e idiomas do host (194)

No entanto, você deve saber como os NULLs são tratados quando precisam ser passados ​​para um programa host. Nenhum idioma padrão do host para o qual uma incorporação é definida oferece suporte a NULLs, o que é outro bom motivo para evitar usá-los no esquema do banco de dados.

(separador)

6.9 Conselho de design para NULLs (195)

É uma boa ideia declarar todas as suas tabelas base com restrições NOT NULL em todas as colunas sempre que possível. NULLs confundem pessoas que não conhecem SQL, e NULLs são caros.

Objeção: NULLs confunde até pessoas que conhecem bem o SQL, veja abaixo.

(195)

NULLs devem ser evitados em CHAVES ESTRANGEIRAS. O SQL permite esse relacionamento de "benefício da dúvida", mas pode causar perda de informações nas consultas que envolvem junções. Por exemplo, dado um código de número de peça no Inventário que é referenciado como uma CHAVE ESTRANGEIRA por uma tabela Pedidos, você terá problemas para obter uma lista das peças que possuem um NULL. Este é um relacionamento obrigatório; você não pode solicitar uma peça que não existe.

(separador)

6.9.1 Evitando NULLs dos programas host (197)

Você pode evitar colocar NULLs no banco de dados nos Programas Host com alguma disciplina de programação.

...

  1. Determine o impacto de dados ausentes na programação e nos relatórios: as colunas numéricas com NULLs são um problema, porque as consultas usando funções agregadas podem fornecer resultados enganosos.

(separador)

(227)

O SUM () de um conjunto vazio é sempre NULL. Um dos erros de programação mais comuns cometidos ao usar esse truque é escrever uma consulta que possa retornar mais de uma linha. Se você não pensou sobre isso, pode ter escrito o último exemplo como: ...

(separador)

10.1.1 Fontes de NULLs (242)

É importante lembrar onde os NULLs podem ocorrer. Eles são mais do que apenas um valor possível em uma coluna . Funções agregadas em conjuntos vazios, OUTER JOINs, expressões aritméticas com NULLs e operadores OLAP retornam NULLs. Essas construções costumam aparecer como colunas em VIEWs.

(separador)

(301)

Outro problema com NULLs é encontrado quando você tenta converter predicados IN em predicados EXISTS.

(separador)

16.3 O predicado ALL e as funções Extrema (313)

É contra-intuitivo a princípio que esses dois predicados não sejam os mesmos no SQL:

...

Mas você precisa se lembrar das regras para as funções extremas - elas eliminam todos os NULLs antes de retornar os valores maiores ou menores. O predicado ALL não descarta NULLs, para que você possa obtê-los nos resultados.

(separador)

(315)

No entanto, a definição no padrão é redigida em negativo, para que os NULLs obtenham o benefício da dúvida. ...

Como você pode ver, é uma boa idéia evitar NULLs em restrições UNIQUE.

Discutindo GROUP BY:

NULLs são tratados como se fossem todos iguais e formam seu próprio grupo. Cada grupo é então reduzido a uma única linha em uma nova tabela de resultados que substitui a antiga.

Isso significa que para a cláusula GROUP BY NULL = NULL não é avaliado como NULL, como em 3VL, mas é avaliado como TRUE.

O padrão SQL é confuso:

ORDER BY e NULLs (329)

Se um valor de chave de classificação que é NULL é considerado maior ou menor que um valor não-NULL é definido pela implementação, mas ...

... Existem produtos SQL que fazem isso de qualquer maneira.

Em março de 1999, Chris Farrar levantou uma pergunta de um de seus desenvolvedores que o levou a examinar uma parte do SQL Standard que eu pensava entender . Chris encontrou algumas diferenças entre o entendimento geral e a redação real da especificação .

E assim por diante. Eu acho que é o suficiente por Celko.

Data CJ em SQL NULLs

A data CJ é mais radical quanto aos NULLs: evite NULLs no SQL, ponto final. De fato, o capítulo 4 de sua SQL e a teoria relacional: Como escrever um código SQL preciso é intitulado "SEM DUPLICADOS, SEM NULOS", com os subcapítulos "4.4 O que há de errado com os nulos?" e "4.5 Evitando nulos no SQL" (siga o link: graças ao Google Livros, você pode ler algumas páginas on-line).

Fabian Pascal em SQL NULLs

De suas questões práticas no gerenciamento de banco de dados - uma referência para o profissional que pensa (sem trechos on-line, desculpe):

10.3 Implicações práticas

10.3.1 NULL SQL

... O SQL sofre dos problemas inerentes à 3VL, bem como de muitas peculiaridades, complicações, contra-intuitividade e erros definitivos [10, 11]; entre eles estão os seguintes:

  • Funções agregadas (por exemplo, SUM (), AVG ()) ignoram NULLs (exceto COUNT ()).
  • Uma expressão escalar em uma tabela sem linhas é avaliada incorretamente como NULL, em vez de 0.
  • A expressão "NULL = NULL" é avaliada como NULL, mas na verdade é inválida no SQL; ainda ORDER BY trata NULLs como iguais (o que eles precedem ou seguem valores "regulares" é deixado para o fornecedor do DBMS).
  • A expressão "x IS NOT NULL" não é igual a "NOT (x IS NULL)", como é o caso em 2VL.

...

Todos os dialetos SQL implementados comercialmente seguem essa abordagem de 3VL e, portanto, não apenas apresentam esses problemas, mas também apresentam problemas de implementação específicos, que variam entre os produtos .

MaD70
fonte
4
"E este foi o meu ponto: NULL, como valor, é uma" besta estranha "." - isso é porque NULLnão é um valor.
Pavel Minaev 04/12/2009
1
Além disso, o SQL Server não fornece (NULL = NULL) -> FALSE. Para citar a documentação de ANSI_NULLS: "Quando ON é especificado, todas as comparações com um valor nulo são avaliadas como DESCONHECIDAS . Quando OFF é especificado, comparações de valores não-UNICODE com um valor nulo são avaliadas como TRUE se ambos os valores forem NULL."
Pavel Minaev
@ Pavel Minaev: a) e quão VERDADEIRO é melhor que FALSO? b) Se não é um valor, por que é atribuído como parte dos valores das variáveis?
MaD70
1
>> Desde dezembro, vamos usar um exemplo sazonal. Eu tenho dois presentes embaixo da árvore. Agora, você me diz se eu tenho duas da mesma coisa ou não. ..... sim, você fez na medida em que tem duas coisas e, no que diz respeito a você agora , na medida do seu conhecimento atual, elas são exatamente iguais para você
Brad Thomas
3
null = null deve ser verdadeiro. null é um valor bem definido que pode representar um valor desconhecido , mas também pode representar a ausência de um valor. Cabe ao desenvolvedor decidir o que nulo representa, mas nulo em si é absolutamente um valor e nulo é nulo = nulo. Qualquer outra implementação está sujeita a desastres, porque você está injetando lógica ternária em predicados que são fundamentalmente booleanos. Estou aplaudido que isso está se tornando permanente na configuração no servidor SQL. OFF OFF OFF OFF com ele.
Triynko 23/09
9

Talvez isso dependa, mas pensei que NULL=NULLavalia NULLcomo a maioria das operações com NULL como um operando.

Michael Krelin - hacker
fonte
9

Só porque você não sabe o que são duas coisas, não significa que são iguais. Se, quando você pensa em NULLvocê, pensa em "NULL" (string), provavelmente deseja um teste de igualdade diferente como o IS DISTINCT FROMAND do PostgresqlIS NOT DISTINCT FROM

Dos documentos do PostgreSQL sobre "Funções e operadores de comparação"

expressão IS DISTINCT FROMexpressão

expressão IS NOT DISTINCT FROMexpressão

Para entradas não nulas, IS DISTINCT FROMé o mesmo que o <>operador. No entanto, se ambas as entradas forem nulas, retornará false e, se apenas uma entrada for nula, retornará true. Da mesma forma, IS NOT DISTINCT FROMé idêntico a =entradas não nulas, mas retorna true quando ambas as entradas são nulas e false quando apenas uma entrada é nula. Assim, essas construções agem efetivamente como se nulo fosse um valor de dados normal, em vez de "desconhecido".

Evan Carroll
fonte
5

O conceito de NULL é questionável, para dizer o mínimo. Codd introduziu o modelo relacional e o conceito de NULL em contexto (e propôs mais de um tipo de NULL!) No entanto, a teoria relacional evoluiu desde os escritos originais de Codd: algumas de suas propostas foram descartadas (por exemplo, chave primária) e outros nunca pegaram (por exemplo, operadores teta). Na teoria relacional moderna (teoria verdadeiramente relacional, devo enfatizar) NULL simplesmente não existe. Veja O Terceiro Manifesto. http://www.thethirdmanifesto.com/

A linguagem SQL sofre o problema de compatibilidade com versões anteriores. O NULL chegou ao SQL e estamos presos a ele. Indiscutivelmente, a implementação do NULLSQL é falha (a implementação do SQL Server torna as coisas ainda mais complicadas devido à sua ANSI_NULLSopção).

Eu recomendo evitar o uso de colunas NULLable nas tabelas base.


Embora talvez eu não deva ficar tentado, eu só queria afirmar uma correção minha sobre como NULLfunciona o SQL:

NULL= NULLavalia como UNKNOWN.

UNKNOWN é um valor lógico.

NULL é um valor de dados.

É fácil provar, por exemplo

SELECT NULL = NULL

gera corretamente um erro no SQL Server. Se o resultado fosse um valor de dados, esperamos ver NULL, como algumas respostas aqui (erradamente) sugerem que sim.

O valor lógico UNKNOWNé tratado de maneira diferente no SQL DML e no SQL DDL, respectivamente.

No SQL DML, UNKNOWNfaz com que as linhas sejam removidas do conjunto de resultados.

Por exemplo:

CREATE TABLE MyTable
(
 key_col INTEGER NOT NULL UNIQUE, 
 data_col INTEGER
 CHECK (data_col = 55)
);

INSERT INTO MyTable (key_col, data_col)
   VALUES (1, NULL);

O INSERTêxito desta linha, mesmo que a CHECKcondição seja resolvida NULL = NULL. Isso ocorre devido ao padrão SQL-92 ("ANSI"):

11.6 definição de restrição de tabela

3)

Se a restrição de tabela for uma definição de restrição de verificação, deixe SC ser a condição de pesquisa imediatamente contida na definição de restrição de verificação e seja T o nome da tabela incluído no descritor de restrição de tabela correspondente; a restrição de tabela não é satisfeita se e somente se

EXISTE (SELECIONE * DE T ONDE NÃO (SC))

é verdade.

Leia isso novamente com atenção, seguindo a lógica.

Em inglês simples, nossa nova linha acima recebe o 'benefício da dúvida' sobre ser UNKNOWNe permissão para passar.

No SQL DML, a regra para a WHEREcláusula é muito mais fácil de seguir:

A condição de pesquisa é aplicada a cada linha de T. O resultado da cláusula where é uma tabela das linhas de T para as quais o resultado da condição de pesquisa é verdadeiro.

Em inglês simples, as linhas avaliadas UNKNOWNsão removidas do conjunto de resultados.

um dia quando
fonte
5

No technet, há uma boa explicação de como os valores nulos funcionam.

Nulo significa desconhecido.

Portanto, a expressão booleana

valor = nulo

não avalia como falso, avalia como nulo, mas se esse for o resultado final de uma cláusula where, nada será retornado. Essa é uma maneira prática de fazer isso, pois retornar nulo seria difícil de conceber.

É interessante e muito importante entender o seguinte:

Se em uma consulta tivermos

where (value=@param Or @param is null) And id=@anotherParam

e

  • valor = 1
  • @param é nulo
  • id = 123
  • @ anotherParam = 123

então

"value = @ param" avalia como nulo
"@param é nulo" avalia como true
"id = @ anotherParam" avalia como true

Portanto, a expressão a ser avaliada se torna

(nulo ou verdadeiro) e verdadeiro

Podemos ficar tentados a pensar que aqui "null Or true" será avaliado como null e, portanto, toda a expressão se tornará nula e a linha não será retornada.

Isto não é verdade. Por quê?

Como "null Or true" é avaliado como true, o que é muito lógico, pois se um operando for verdadeiro com o operador Or, não importa o valor do outro operando, a operação retornará true. Portanto, não importa que o outro operando seja desconhecido (nulo).

Finalmente, temos true = true e, portanto, a linha será retornada.

Nota: com a mesma lógica clara que "null Or true" avalia como true, "null And true" avalia como null.

Atualização:
Ok, apenas para completar, quero adicionar o restante aqui também, o que resulta bastante divertido em relação ao acima.

"nulo ou falso" é avaliado como nulo, "nulo e falso" é avaliado como falso. :)

A lógica ainda é obviamente tão evidente quanto antes.

Magnus
fonte
4

Porque NULLsignifica 'valor desconhecido' e dois valores desconhecidos não podem ser iguais.

Então, se a nossa lógica NULLN ° 1 é igual a NULLN ° 2, então temos que dizer isso de alguma forma:

SELECT 1
WHERE ISNULL(nullParam1, -1) = ISNULL(nullParam2, -1)

onde o valor conhecido -1N ° 1 é igual a -1N ° 2

armênio
fonte
nullParam1 = -1e nullParam2 =NULLe airplain acidente .... deve serISNULL(NULLIF(@nullParam1, @nullParam2), NULLIF(@nullParam2, nullParam1)) IS NULL
Selvin
4

As respostas aqui parecem vir de uma perspectiva de CS, então eu quero adicionar uma da perspectiva de desenvolvedor.

Para um desenvolvedor, NULL é muito útil. As respostas aqui dizem que NULL significa desconhecido, e talvez na teoria do CS seja verdade, não se lembre, já faz um tempo. No desenvolvimento atual, pelo menos na minha experiência, isso acontece cerca de 1% das vezes. Os outros 99% são usados ​​para casos em que o valor não é DESCONHECIDO, mas é sabido que é ausente.

Por exemplo:

  • Client.LastPurchase, para um novo cliente. Não é desconhecido, sabe-se que ele ainda não fez uma compra.

  • Ao usar um ORM com um mapeamento Tabela por hierarquia de classes , alguns valores simplesmente não são mapeados para determinadas classes.

  • Ao mapear uma estrutura de árvore, uma raiz geralmente teráParent = NULL

  • E muitos mais...

Tenho certeza que a maioria dos desenvolvedores, em algum momento WHERE value = NULL, escreveu , não obteve nenhum resultado, e foi assim que aprenderam sobre IS NULLsintaxe. Veja quantos votos essa pergunta e as que têm estão vinculadas.

Os bancos de dados SQL são uma ferramenta e devem ser projetados da maneira mais fácil para os usuários entenderem.

AlexDev
fonte
1
Todo mundo parece gritar "NULL é desconhecido" e justifica o comportamento. Sim, se isso é uma premissa, então 3VL talvez seja a resposta. Mas em quase todos os bancos de dados nos quais trabalho, NULL significa ausente. Desculpe sua voz está perdida no deserto @AlexDev
John Rees
3

NULL não é igual a nada, nem a si próprio. Minha solução pessoal para entender o comportamento do NULL é evitar usá-lo o máximo possível :).

Chris R. Timmons
fonte
1
poderia muito bem ser igual a tudo, como é no caso da esquerda / direita / junções externas ...
Miguel Ventura
5
Que resposta tola e improdutiva. O mesmo poderia ser dito para crianças do ensino fundamental sobre álgebra, mas, sem realmente reconhecer o que está tentando resolver, isso pareceria bobo, o que aconteceu.
Evan Carroll
2
@ Evan: Na verdade, evitar o NULL é uma solução sólida. A lógica com três valores não é incontroversa e muitas pessoas acham que o SQL seria melhor sem NULL e toda a complexidade (necessária) que isso implica.
sleske
3
"Muitas pessoas" é uma palavra comum, e "não incontroverso" é uma maneira de esconder o mais simples "controverso", do qual a 3VL não é.
Evan Carroll
"NULL não é igual a nada, nem a si mesmo." seguindo essa lógica, <somevalue>! = NULL deve retornar true. No universo estranho do SQL, no entanto, é falso.
Tom Lint
3

A pergunta:
um desconhecido é igual a outro desconhecido?
(NULL = NULL)
Essa pergunta é algo que ninguém pode responder, por padrão, é true ou false dependendo da configuração de ansi_nulls.

No entanto, a pergunta:
essa variável desconhecida é desconhecida?
Esta pergunta é bem diferente e pode ser respondida com verdadeiro.

nullVariable = null está comparando os valores
nullVariable is null está comparando o estado da variável

user224385
fonte
3

A confusão surge do nível de indireção (abstração) resultante do uso de NULL .

Voltando à analogia "o que há sob a árvore de Natal", "Desconhecido" descreve o estado do conhecimento sobre o que está na Caixa A.

Portanto, se você não sabe o que há na Caixa A, diz que é "Desconhecido", mas isso não significa que "Desconhecido" esteja dentro da caixa . Algo diferente de desconhecido está na caixa, possivelmente algum tipo de objeto, ou possivelmente nada está na caixa.

Da mesma forma, se você não souber o que está na Caixa B, poderá rotular seu estado de conhecimento sobre o conteúdo como "Desconhecido".

Então aqui está o kicker: O seu estado de conhecimento sobre Box A é igual ao seu estado de conhecimento sobre Box B . (O seu estado de conhecimento em ambos os casos é "Desconhecido" ou "Não sei o que há na caixa".) Mas o conteúdo das caixas pode ou não ser igual.

Voltando ao SQL, idealmente, você só poderá comparar valores quando souber o que são. Infelizmente, o rótulo que descreve a falta de conhecimento é armazenado na própria célula , por isso somos tentados a usá-lo como um valor. Mas não devemos usar isso como um valor, porque levaria a "o conteúdo da Caixa A é igual ao conteúdo da Caixa B quando não sabemos o que está na Caixa A e / ou não sabemos o que está na Caixa B. (Logicamente, a implicação "se eu não souber o que está na caixa A e se não souber o que está na caixa B, então o que está na caixa A = o que está na caixa B" é falso.)

Yay, cavalo morto.

TomEberhard
fonte
3

O MSDN tem um bom artigo descritivo sobre nulos e a lógica de três estados que eles geram.

Em resumo, a especificação SQL92 define NULL como desconhecido, e NULL usado nos seguintes operadores causa resultados inesperados para os não iniciados:

= operator NULL   true   false 
NULL       NULL   NULL   NULL
true       NULL   true   false
false      NULL   false  true

and op     NULL   true   false 
NULL       NULL   NULL   false
true       NULL   true   false
false      false  false  false

or op      NULL   true   false 
NULL       NULL   true   NULL
true       true   true   true
false      NULL   true   false
Paul Wagland
fonte
Mas a questão não é sobre 3VL (lógica de três valores), é sobre a propriedade reflexiva da igualdade.
MaD70
Para ser mais preciso, como finalmente detalhei em minha resposta, surgem problemas quando a igualdade é interpretada em uma 3VL, de modo que a propriedade reflexiva da igualdade nem sempre é avaliada como verdadeira.
MaD70
1

null é desconhecido no sql, portanto não podemos esperar que duas incógnitas sejam iguais.

No entanto, você pode obter esse comportamento definindo ANSI_NULLS como Desativado (ativado por padrão). Você poderá usar o operador = para valores nulos.

SET ANSI_NULLS off
if null=null
print 1
else 
print 2
set ansi_nulls on
if null=null
print 1
else 
print 2
ps.
fonte
2
Isso é todo tipo de não . O mundo tem uma definição de null, aprenda a entendê-lo ou apenas altere a tabela para ter tipos int e atualizar as colunas.
Evan Carroll
3
Eu realmente não recomendo o SET ANSI_NULLS. Eu descobri o ANSI_NULLS da maneira mais difícil. Mas é sempre bom conhecer todas as opções disponíveis, especialmente quando você se depara com uma linha que diz Where SomeId = null Como você entenderia essa linha sem conhecer ANSI_NULLS. Do jeito que eu olho, meu post foi útil .. :)
ps.
1

Você trabalha para o governo registrando informações sobre os cidadãos. Isso inclui o ID nacional de todas as pessoas no país. Uma criança foi deixada na porta de uma igreja cerca de 40 anos atrás, ninguém sabe quem são seus pais. O ID do pai desta pessoa é NULL. Existem duas pessoas assim. Contar pessoas que compartilham o mesmo ID do pai com pelo menos uma outra pessoa (pessoas que são irmãos). Você conta esses dois também?

A resposta é não, você não, porque não sabemos se são irmãos ou não.

Suponha que você não tenha uma NULLopção e, em vez disso, use algum valor predeterminado para representar “o desconhecido”, talvez uma string vazia ou o número 0 ou um caractere *, etc. Então você teria em suas consultas que * = * , 0 = 0 e “” = “”, etc. Isso não é o que você deseja (como no exemplo acima) e, como muitas vezes você esquece desses casos (o exemplo acima é um caso de franja clara, fora do pensamento cotidiano comum ), você precisa lembrar o idioma que NULL = NULLnão é verdadeiro.

Necessidade é a mãe da invenção.

Rashad Saleh
fonte
0

Apenas uma adição a outras respostas maravilhosas:

AND: The result of true and unknown is unknown, false and unknown is false,
while unknown and unknown is unknown.

OR: The result of true or unknown is true, false or unknown is unknown, while unknown or unknown is unknown.

NOT: The result of not unknown is unknown
Kiren Siva
fonte
0

Se você está procurando uma expressão retornando true para dois NULLs, pode usar:

SELECT 1 
WHERE EXISTS (
    SELECT NULL
    INTERSECT
    SELECT NULL
)

É útil se você deseja replicar dados de uma tabela para outra.

Piotr
fonte
0

O teste de igualdade, por exemplo, em uma declaração de caso quando a cláusula, pode ser alterado de

XYZ = NULL 

para

XYZ IS NULL

Se eu quiser tratar espaços em branco e string vazia como iguais a NULL, geralmente também uso um teste de igualdade como:

(NULLIF(ltrim( XYZ ),'') IS NULL)
Allan F
fonte