SQL: cadeia vazia vs valor NULL


72

Sei que esse assunto é um pouco polêmico e há muitos artigos / opiniões circulando pela Internet. Infelizmente, a maioria deles assume que a pessoa não sabe qual é a diferença entre NULL e string vazia. Eles contam histórias sobre resultados surpreendentes com junções / agregados e geralmente fazem lições de SQL um pouco mais avançadas. Ao fazer isso, eles perdem completamente o objetivo e são, portanto, inúteis para mim. Portanto, espero que esta pergunta e todas as respostas avancem um pouco no assunto.

Suponhamos que eu tenha uma tabela com informações pessoais (nome, nascimento etc.) em que uma das colunas seja um endereço de email com o tipo varchar. Assumimos que, por algum motivo, algumas pessoas podem não querer fornecer um endereço de email. Ao inserir esses dados (sem email) na tabela, há duas opções disponíveis: defina a célula como NULL ou defina a string vazia (''). Vamos supor que estou ciente de todas as implicações técnicas da escolha de uma solução em detrimento de outra e posso criar consultas SQL corretas para qualquer um dos cenários. O problema é mesmo quando ambos os valores diferem no nível técnico, eles são exatamente os mesmos no nível lógico. Depois de olhar para NULL e '', cheguei a uma única conclusão: não sei o endereço de e-mail do cara. Também não importa o quanto eu tentei, Não consegui enviar um email usando uma seqüência de caracteres nula ou vazia, portanto, aparentemente, a maioria dos servidores SMTP por aí concorda com minha lógica. Então, eu costumo usar NULL onde não sei o valor e considero uma string vazia uma coisa ruim.

Após discussões intensas com os colegas, vim com duas perguntas:

  1. Estou certo ao supor que o uso de uma string vazia para um valor desconhecido está causando um banco de dados "mentir" sobre os fatos? Para ser mais preciso: usando a idéia do SQL de o que é valor e o que não é, posso concluir: temos um endereço de email, apenas descobrindo que não é nulo. Porém, mais tarde, ao tentar enviar um e-mail, chegarei a uma conclusão contraditória: não, não temos endereço de e-mail, esse banco de dados @! # $ Deve estar mentindo!

  2. Existe algum cenário lógico no qual uma string vazia '' possa ser uma transportadora tão boa de informações importantes (além de valor e sem valor), que seria problemático / ineficiente para armazenar de qualquer outra maneira (como coluna adicional). Eu já vi muitas postagens alegando que, às vezes, é bom usar uma string vazia junto com valores reais e NULLs, mas até agora não vi um cenário que fosse lógico (em termos de design do SQL / DB).

PS Algumas pessoas ficam tentadas a responder, que é apenas uma questão de gosto pessoal. Eu não concordo Para mim, é uma decisão de design com consequências importantes. Então, eu gostaria de ver respostas em que a opinião sobre isso é apoiada por alguns motivos lógicos e / ou técnicos.


11
Você está ciente de que, no Oracle, a cadeia vazia é NULL?
user281377

8
@ammoQ: o tratamento da Oracle de cadeias de comprimento zero não é padrão. Além disso, ''mesmo no Oracle, não é o mesmo que NULL. Por exemplo, ao atribuir uma CHAR(1)coluna, o valor ''resultará em ' '(ou seja, um espaço), não NULL. Além disso, se Jacek estava usando Oracle, esta questão provavelmente não até mesmo chegar :-)
Dean Harding

2
Dean: Você está certo sobre o exemplo char (1), mas esse é outro WTF, já que é '' IS NULLavaliado trueem PL / SQL.
user281377

"Estou certo ao supor que o uso de uma string vazia para um valor desconhecido está causando um banco de dados" mentir "sobre os fatos?" se os usuários da sua empresa não se importam com o desconhecido versus o vazio, a mentira é importante?
Andy

Se você deve seguir o caminho de usar uma string ... por favor, verifique se está vazia. Para o bem de todos os desenvolvedores, não deixe que uma string com um espaço represente seu valor desconhecido. Eu te imploro.
Airn5475

Respostas:


83

Eu diria que NULLé a escolha correta para "nenhum endereço de email". Existem muitos endereços de email "inválidos" e "" (sequência vazia) é apenas um. Por exemplo, "foo" não é um endereço de email válido, "a @ b @ c" não é válido e assim por diante. Portanto, apenas porque "" não é um endereço de email válido, não há razão para usá-lo como o valor "nenhum endereço de email".

Acho que você está certo ao dizer que "" não é a maneira correta de dizer "Não tenho um valor para esta coluna". "" é um valor.

Um exemplo de onde "" pode ser um valor válido, separado para NULLo nome do meio de uma pessoa. Nem todo mundo tem um nome do meio, então você precisa diferenciar entre "sem nome do meio" ("" - string vazia) e "Não sei se essa pessoa tem um nome do meio ou não" ( NULL). Provavelmente existem muitos outros exemplos em que uma string vazia ainda é um valor válido para uma coluna.


5
Concordo plenamente. NULL existe por uma razão. SELECIONE A CONTAGEM (*) DA SUA TABELA ONDE O EMAIL É [NÃO] NULL é a maneira de fazê-lo, não a comparação de cadeias que tenderá a ser mais lenta (mesmo que para cadeias vazias, suponho, mas não tenho certeza dessa :):
LudoMC

5
Acho NULLque não significa que não há endereço de email, acho que significa que o endereço de email atualmente não é conhecido, não existe ou é impossível preencher por outros motivos. Felizmente, provavelmente não existe uma situação em que alguém queira manter em um banco de dados as informações sobre pessoas que realmente não têm e não planejam ter nenhum endereço de e-mail; caso contrário, um campo booleano separado provavelmente seria necessário.
Alex8

9
@Alexey - NULL significa que não há valor. Como outros já apontaram, uma string vazia é um valor.
Ramhound 9/08/12

3
@ Ramhound, concordo que a string vazia é um valor, e que NULL vagamente significa "não há valor". Acabei de explicar minha interpretação de "sem valor". Na minha opinião, não é o mesmo que "a pessoa não abriu nenhuma conta de email". É um pouco "nenhum endereço de e-mail registrado para essa pessoa".
9288 Alexey

5
@ Ramhound NULL significa que não há valor. Uma pessoa sem um nome do meio não tem valor lá. Portanto, NULL também deve ser usado em uma coluna inicial do meio ... O que é completamente oposto ao argumento apresentado nesta resposta.
Izkata 13/08/2012

41

Ao concordar com os comentários acima, eu acrescentaria este argumento como uma motivação principal:

  1. É óbvio para qualquer programador que esteja olhando para um banco de dados que um campo marcado como NULL seja um campo opcional. (ou seja, o registro não requer dados para essa coluna)
  2. Se você marcar um campo como NÃO NULL, qualquer programador deve assumir intuitivamente que é um campo obrigatório.
  3. Em um campo que permite nulos, os programadores devem esperar ver nulos em vez de cadeias vazias.

Para fins de codificação intuitiva de auto-documentação, use NULL em vez de cadeias vazias.


4
+1 Este é o argumento de "menor espanto" em relação aos desenvolvedores contra cadeias vazias. Nenhum desenvolvedor que vier depois esperaria que cadeias vazias fossem usadas para representar "nenhum endereço de email".
Thomas

6

No seu exemplo, se for um valor diretamente do campo da web - eu usaria uma string vazia. Se o usuário puder optar por especificar que ele não deseja fornecer email ou pode excluí-lo -, então NULL.

Aqui estão os links que você pode considerar: https://stackoverflow.com/questions/405909/null-vs-empty-when-dealing-with-user-input/405945#405945

--- editado (em resposta ao comentário de Thomas) ---

Os bancos de dados não vivem sem aplicativos que os utilizam. Definir NULL ou '' não tem valor, se o aplicativo não puder usá-lo corretamente.

Considere um exemplo em que o usuário está preenchendo o formulário LONG e pressione Enter, que enviará uma solicitação persistente ao servidor. Ele pode estar no meio da digitação do email. Provavelmente você deseja armazenar o que ele tem no campo de email, para que mais tarde ele possa finalizá-lo. E se ele inserisse apenas um caractere? E se ele inserisse um caractere e o excluísse? Quando o email não é necessário, algumas vezes os usuários desejam excluí-lo: a maneira mais fácil de limpar o campo. Também no caso de não ser necessário o e-mail, vale a pena validá-lo antes de enviá-lo.

Outro exemplo: o usuário fornece email como spam para @ [bigcompany] .com - nesse caso, não há necessidade de enviar email, mesmo que ele exista e seja válido (e pode até existir). Enviar um desses talvez seja barato, mas se houver 10 mil usuários com esses emails para assinaturas diárias, essa validação poderá economizar muito tempo.


7
-1. Se o banco de dados está dirigindo um site ou não, é irrelevante. Projetar bancos de dados é um mundo diferente do web design. O banco de dados deve ser projetado para capturar fatos sobre o domínio comercial, independentemente da interface usada para gravar nele. Pela sua lógica, você deve usar nulos se, por coincidência, o primeiro aplicativo for um executável? O que acontece se o primeiro aplicativo for um aplicativo Web, mas o próximo aplicativo for um aplicativo móvel? Projete o banco de dados para capturar fatos usando regras de normalização e projete o site para gravar nele.
Thomas

Fico feliz que você tenha aprendido a escrever e comentar neste site :) Ainda acredito que o DB deve suportar o aplicativo que o utiliza. Verifique minha resposta editada.
Konstantin Petrukhnov

4
Os bancos de dados não vivem sem aplicativos que os utilizam. Na minha experiência, isso simplesmente não é verdade e míope. Quase sempre, o banco de dados é usado fora do aplicativo para o qual foi projetado. Em geral, os bancos de dados sobrevivem mais do que os aplicativos para os quais foram criados. Os bancos de dados devem ser projetados para coletar fatos sobre os negócios e a interface do usuário deve ser criada para ler e gravar no banco de dados, e não o contrário. O design relacional é uma mentalidade totalmente diferente da design do aplicativo.
Thomas

2
Exemplos em que o banco de dados não é usado apenas pelo aplicativo original : relatórios, integrações com outros sistemas.
Thomas

11
Como Thomas indicou, os bancos de dados podem e geralmente são usados ​​por mais de um aplicativo, o que aumenta a idéia de manter os dados do banco de dados limpos. Se você não quiser / não puder manipular NULLs no seu aplicativo, poderá simplesmente substituí-los pelos seus "valores mágicos" (bela descrição Thomas) na sua camada de acesso a dados. Dessa forma, quaisquer aplicativos futuros que desejam acessar o banco de dados não precisam conhecer / estar em conformidade com os valores mágicos dos aplicativos originais.
precisa saber é o seguinte

5

Acho que a resposta de Dean Hardings cobre isso muito bem. Dito isso, eu gostaria de mencionar que, ao falar sobre NULLs vs strings vazias no nível do banco de dados, você deve pensar sobre seus outros tipos de dados. Você armazenaria a data mínima quando nenhuma data for fornecida? ou -1 quando nenhum int é fornecido? Armazenar um valor quando você não tem valor significa que você deve acompanhar todo um intervalo de valores não. Pelo menos um para cada tipo de dado (possivelmente mais quando você obtém casos em que -1 é um valor real, portanto você precisa ter alguma alternativa etc). Se você precisa / deseja fazer algo "fudgy" no nível do aplicativo, isso é uma coisa, mas não é necessário poluir seus dados.


2
+1 - É o que chamo de "Solução de valor mágico". Temos que criar um valor mágico para cada tipo de dados para representar a ausência de um valor. Além disso, em algumas colunas, o valor mágico comum é ou se torna um valor legítimo e, portanto, é necessário um novo valor mágico.
Thomas

5

Infelizmente, o Oracle confundiu a representação da sequência VARCHAR de comprimento zero com a representação NULL. Ambos são representados internamente por um único byte com valor zero. Isso torna a discussão muito mais difícil.

Muita confusão em torno do NULL gira em torno da lógica de três valores . Considere o seguinte pseudocódigo:

if ZIPCODE = NULL
    print "ZIPCODE is NULL"
else if ZIPCODE <> NULL
    print "ZIPCODE is not NULL"
else print "Something unknown has happened"

Você não esperaria a terceira mensagem, mas é isso que você receberia, sob três lógicas valiosas. Três lógicas valiosas levam as pessoas a inúmeros erros.

Outra fonte de confusão é extrair inferências a partir da ausência de dados, como extrair uma inferência do cachorro que não latia à noite. Freqüentemente, essas inferências não eram o que o escritor do NULL pretendia transmitir.

Dito isto, há muitas situações em que NULL lida com a ausência de dados muito bem e produz exatamente os resultados desejados. Um exemplo são as chaves estrangeiras nos relacionamentos opcionais. Se você usar um NULL para indicar nenhum relacionamento em uma determinada linha, essa linha será removida de uma junção interna, exatamente como seria de esperar.

Além disso, esteja ciente de que, mesmo que você evite NULLS completamente nos dados armazenados (sexta forma normal), se fizer alguma junção externa, ainda precisará lidar com NULLS.


4

Use Nulo.

Não há nenhum ponto em armazenar um valor de '', basta fazer o campo na tabela anulável. Também torna as consultas mais óbvias.

Qual consulta SQL é mais óbvia e legível se você deseja encontrar usuários com um endereço de email?

  1. SELECT * FROM Users WHERE email_address != ''

  2. SELECT * FROM Users WHERE email_address IS NOT NULL

  3. SELECT * FROM Users WHERE email_address != '' and email_address IS NOT NULL

Eu diria que 2 é. Embora 3 seja mais robusto nos casos em que há dados ruins armazenados.

No caso do endereço de email no formulário, que é opcional, ele também deve ser refletido na tabela. No SQL, é um campo anulável, o que significa que não é conhecido.

Não consigo pensar em nenhum valor comercial razoável para armazenar uma string vazia em uma tabela que não seja simplesmente um design ruim. É como armazenar um valor de string de 'NULL' ou 'BLANK', e fazer com que os desenvolvedores assumam que é nulo ou vazio. Para mim, isso é um design ruim. Por que armazenar isso quando há NULL ??

Basta usar NULL e você deixará todo mundo um pouco mais feliz.

MAIS INFORMAÇÕES:

O SQL usa um sistema lógico de três valores: True, False e Unknown.

Para uma explicação melhor e mais detalhada, recomendo que os desenvolvedores leiam: Consultas SQL - além de TRUE e FALSE .


3

para a questão técnica específica, o problema não é nulo versus cadeia vazia, é uma falha de validação . Uma string vazia não é um endereço de email válido!

para a pergunta filosófica, a resposta é semelhante: valide suas entradas. Se uma sequência vazia for um valor válido para o campo em questão, espere e codifique; Caso contrário, use null.

Uma string vazia seria uma entrada válida para responder à pergunta: O que a mímica disse à girafa?


Mesmo com a melhor intenção do mundo, a validação pode não resolver esse problema - ele ainda pode precisar usar um método que lide com linhas em que todas as colunas devem ser fornecidas com algum tipo de valor. Nesse caso, a pergunta permanecerá - que valor usar quando não houver valor? E a resposta será obviamente: o valor que não indica valor. Nos bancos de dados, isso geralmente é NULL.
jmoreno

2

Eu poderia pensar em uma razão para ter NULL e a string vazia:

  • Você tem endereços de email válidos: me@example.com
  • Você não possui nenhum (e provavelmente deve solicitar um): NULL
  • Você sabe que essa pessoa não tem um endereço de email: Empty String.

No entanto, eu não recomendaria isso e use um campo separado para perguntar se você sabe que não existe nenhum.


1

A questão que eu entendo, é quais interpretações de NULL e string vazia devem ser escolhidas. Isso depende de quantos estados o campo particualar pode estar.

A interpretação depende de como o banco de dados está sendo acessado. Se houver uma camada no código que abstraia completamente o banco de dados, a escolha de qualquer política (incluindo dois coulmn) que funcione é completamente aceitável. (Documentar claramente a política é importante). No entanto, se o banco de dados estiver sendo acessado em vários locais, você deverá usar um esquema muito simples, pois o código será mais difícil de manter e poderá estar errado neste caso.


1

Bem, basicamente, no nível lógico, não há diferença entre o valor "inválido" e "sem entrada do usuário", eles são apenas "casos especiais" na maioria das vezes. Caso de erro.

Ter nulo requer espaço adicional: ceil (column_with_null / 8) em bytes / por linha.

Célula vazia e nulo são maneiras de marcar que algo está errado / deve ser o padrão. Por que você precisaria de 2 estados "errados"? Por que usar NULLs se eles ocupam espaço adicional e significam exatamente o mesmo que cadeias vazias? Isso apenas introduzirá confusão e redundância quando você tiver duas coisas que significam (o que poderia significar) exatamente o mesmo; é fácil esquecer que você deve usar NULLs em vez de cadeias vazias (se, por exemplo, o usuário omitir alguns campos).

E seus dados podem se tornar uma bagunça. Em um mundo perfeito, você diria "os dados sempre estarão corretos e eu lembrarei" ... mas quando as pessoas precisam trabalhar em equipe e nem todo mundo está exatamente no seu nível, não é incomum ver ONDE (aa. xx <> '' E bb.zz NÃO É NULL)

Então, em vez de corrigir os membros da minha equipe todos os dias, eu apenas imponho uma regra simples. Sem valores nulos, NUNCA!

Contar valores NON-NULL é mais rápido ... pergunta simples: para que você precisaria fazer isso?


Lembro-me vagamente de ler em algum lugar que usar NULL é realmente um custo (tanto em termos de computação quanto de armazenamento) para o banco de dados. Tão bom ponto de trazer essa fórmula.
Jacek Prucia

Não esqueça que uma VARCHARcoluna precisará de pelo menos 1 byte para armazenar o comprimento da string, mesmo que seja zero.
Dan04

Célula vazia e nulo são maneiras de marcar que algo está errado . Não é verdade. Um nulo é uma maneira de indicar uma ausência de um valor. Aposto que a maioria dos RDBMS usa uma matriz de bits em cada linha para indicar quais colunas são nulas. Assim, o espaço adicional é tão pequeno que é irrelevante. Preocupar-se com o processamento adicional é uma otimização prematura e não será nada comparado aos obstáculos de velocidade criados para outros desenvolvedores "descobrirem" que você usou intencionalmente seqüências de caracteres vazias.
Thomas

3
Nenhum valor nulo . Esta é a abordagem de avestruz. "Vamos enfiar a cabeça na areia e declarar que valores ausentes não existem". Isso geralmente leva à Magic Value Solution, na qual você precisa criar um valor mágico para cada tipo de dados para representar a ausência de um valor.
Thomas

1

Costumo vê-lo não da perspectiva do banco de dados, mas da perspectiva do programa. Sei que essa pergunta é para o clique do SQL, mas, na verdade, quantos usuários acessam os dados diretamente por mais tempo?

Em um programa eu não gosto de nulo / nada. Existem algumas exceções, mas são exatamente isso. E essas exceções são realmente apenas implementações ruins.

Portanto, se o usuário não inseriu o email, deve haver algo que determine se isso é válido ou não. Se um email em branco estiver bom, ele exibirá uma sequência em branco. Se o usuário não colocou um email e isso viola uma regra, o objeto deve indicar isso.

A idéia de ter significado nulo é antiga e é algo que os programadores modernos precisam resolver.

Mesmo no design do banco de dados, por que o campo de email não pode permitir nulos e ter uma cadeia de comprimento zero e outro campo indicando se o usuário inseriu alguma coisa? É pedir muito um DBMS? O banco de dados não deve, na minha opinião, lidar nem com a lógica de negócios nem com a lógica de exibição. Não foi construído para isso e, portanto, faz um trabalho muito ruim de lidar com isso.


por que o campo de email não pode permitir nulos e ter uma cadeia de comprimento zero - Simplificando: porque qualquer desenvolvedor que saiba alguma coisa sobre bancos de dados nunca esperaria que as cadeias vazias tivessem um significado mágico. Você está tentando criar seu próprio valor mágico para representar o que já existe fundamentalmente em todos os bancos de dados: um conceito para representar a ausência de um valor. Por que reinventar a roda? Além disso, a idéia de NULLS está muito, muito longe da velha escola. Nulos são fundamentais para entender o design de banco de dados relacional.
Thomas

RI MUITO. Como eu disse de uma perspectiva de programadores, os nulos são quase sempre um problema e quase nunca são necessários para a BUSINESS LOGIC. Pessoalmente, como desenvolvedor, não ligo muito para o design relacional. Se eu fizesse, seria um cara de DB. Se eu recebo um nulo de um banco de dados, quase sempre o converto para algo racional, como uma string vazia, em seguida, deixo meu glorioso design de OOP fazer a mágica. A estrutura cuida desses DBAs nulos e tolos forçar o mundo. Eu sei que os caras da DB têm que lidar com isso e eu sinto por você. Mas como programador não preciso. Eu tenho melhores soluções.
ElGringoGrande

Você "nunca" precisa lidar com nulos. Então, o que você descreve é ​​uma solução de avestruz combinada com a solução de valor mágico. "Ignorarei o fato de que existem valores ausentes e converterei todos os números nulos em -1". Até chegar o dia em que -1 seja um valor real. Deve-se observar que um dos motivos pelos quais a MS adicionou genéricos ao .NET foi solucionar a enorme incompatibilidade de impedâncias entre os bancos de dados e o código dos aplicativos e que girava principalmente em torno da expressão de nulos no código da camada intermediária. Esses "nulos tolos" também existem na lógica de negócios.
Thomas

O fato de algum número inteiro estar ausente no banco de dados (ou é nulo) não significa que eu precise representá-lo com -1 ou evan como um valor nulo (int). Se você acha que é a única maneira de lidar com nulos, não entende muito bem de programação. Lembre-se de que null não é a mesma coisa que nada. Como você disse, null representa um espaço reservado para valores ausentes em algum tipo de estrutura de dados. Isso significa alguma coisa. Raramente, a lógica de negócios (que não é a mesma de nunca) precisa desse conceito, porque trata-se de um valor maior, não de dados. E quando é nulo, raramente é a melhor maneira de representar isso.
ElGringoGrande

Até a lógica de negócios deve levar em consideração (representar) valores ausentes, e isso é verdade na minha experiência, em quase todos os sistemas que vi ou construí nos últimos 20 anos. O banco de dados está modelando os fatos de negócios a serem capturados e armazenados. Se a lógica de negócios quiser interagir com o banco de dados, deve saber como lidar com nulos. Seja uma estrutura personalizada, um valor mágico ou um genérico, é irrelevante. A lógica de negócios precisa da capacidade de lidar com o recebimento de um valor ausente do banco de dados e da capacidade de marcar um valor como ausente no banco de dados.
Thomas

-1

Eu não acho que isso importe muito, mas eu gosto mais quando o NULL está lá.

Quando visualizo os dados exibidos em uma tabela (como no SQL Server Management Studio), posso distinguir melhor um valor ausente se ele diz NULL e o plano de fundo é de cor diferente.

Se eu vir um espaço em branco, sempre me pergunto se ele está realmente vazio ou se há algum espaço em branco ou caracteres invisíveis. Com NULL, é garantido vazio à primeira vista.

insira a descrição da imagem aqui

Normalmente, não distingo os valores no aplicativo, porque é inesperado e estranho que NULL e string vazia signifiquem algo diferente. E na maioria das vezes, adotei uma abordagem defensiva e apenas lidei com os dois estados. Mas para mim, como humano, o NULL é mais fácil de processar quando se olha os dados.


este não parece oferecer nada substancial sobre os pontos feitos e explicado na prévia de 12 respostas
mosquito

@gnat: Eu discordo, ninguém nas respostas mencionou o aspecto da visualização humana dos dados ainda. Há apenas um único valor NULL, mas pode haver muitos valores que parecem uma string vazia (não apenas espaço em branco, mas também existem muitos caracteres unicode de comportamento estranho). Não vejo outra resposta mencionando esse aspecto da questão.
Tom Pažourek 11/08/16

tanto quanto eu posso dizer isso foi muito bem definidos na segunda resposta superior que foi publicado há 5 anos: "É óbvio para qualquer programador olhando para um banco de dados ..." etc
mosquito

@gnat: Entendo o seu ponto, apesar de achar que o autor não significa a mesma coisa. Eu acredito que ele é mais a respeito de que NULL implica campos opcionais, mas uma string vazia também pode ser usada para campos obrigatórios, portanto, NULL é mais lógico para o valor ausente. Eu concordo com ele. Mas minha resposta aponta para o fato de que a cadeia vazia não é tão inequívoca quanto o valor NULL, porque muitas coisas podem parecer cadeias vazias à primeira vista, enquanto na verdade não são cadeias vazias.
Tom Pažourek 11/08/16
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.