Por que o Oracle 9i trata uma string vazia como NULL?

216

Eu sei que não consideram '' como NULL, mas isso não faz muita coisa para me dizer por que este é o caso. Pelo que entendi as especificações SQL, '' não é o mesmo que NULL- um é um dado válido e o outro está indicando a ausência dessas mesmas informações.

Sinta-se à vontade para especular, mas indique se é esse o caso. Se houver alguém da Oracle que possa comentar sobre isso, isso seria fantástico!

Chris R
fonte
9
Sinta-se livre para especular? De alguma forma eu não acho que irá fornecê-lo com o maior conjunto de respostas ..
SCDF
1
Suponho que não, mas não tinha certeza de que haveria alguma certeza sobre o assunto, então pensei em abrir as portas. Parece ter funcionado bem, até agora.
Chris R
Relacionados: dba.stackexchange.com/q/49744/56961
AlikElzin-Kilaka

Respostas:

216

Acredito que a resposta é que o Oracle é muito, muito antigo.

Nos velhos tempos, antes de haver um padrão SQL, a Oracle tomava a decisão de design de que as strings vazias em VARCHAR/ VARCHAR2columns eram NULLe que havia apenas um sentido de NULL (existem teóricos relacionais que diferenciam os dados que nunca foram solicitados, dados em que a resposta existe, mas não é conhecida pelo usuário, dados em que não há resposta etc., todos os quais constituem algum senso de NULL).

No momento em que o padrão SQL apareceu e concordou que isso NULLe a sequência vazia eram entidades distintas, já havia usuários do Oracle que tinham código que supunha que os dois fossem equivalentes. Portanto, a Oracle ficou basicamente com as opções de quebrar o código existente, violar o padrão SQL ou introduzir algum tipo de parâmetro de inicialização que alteraria a funcionalidade de um número potencialmente grande de consultas. A violação do padrão SQL (IMHO) foi a menos perturbadora dessas três opções.

A Oracle deixou em aberto a possibilidade de o VARCHARtipo de dados mudar em uma versão futura para aderir ao padrão SQL (razão pela qual todo mundo usa VARCHAR2no Oracle, pois é garantido que o comportamento desse tipo de dados permanecerá o mesmo daqui para frente).

Justin Cave
fonte
60

Tom Kyte VP da Oracle:

Um varchar de comprimento ZERO é tratado como NULL.

'' não é tratado como NULL.

'' quando atribuído a um caractere (1) se torna '' (os tipos de caracteres são cadeias preenchidas em branco).

'' quando atribuído a um varchar2 (1) torna-se '', que é uma cadeia de comprimento zero e uma cadeia de comprimento zero é NULL no Oracle (não é longa '')

Brian
fonte
17
Uau, Tom é muito irritado. Dado que as perguntas são referentes a uma divergência flagrante do SQL92, você pensaria que ele seria menos exigente com isso ... embora ele esteja cansado de responder.
Chris R
8
O melhor de Tom é que você recebe uma resposta clara, que indica exatamente o que ele pensa. Olhar para alguns dos comentários onde as pessoas têm o texto fala usado na Pergunte Tom
Chris Gill
9
Mas seria mais preciso se a segunda linha foi alterada para '' nem sempre é tratada como NULL.
precisa saber é o seguinte
2
@ypercube A citação não é mais precisa alterando a palavra realmente usada por Tom. Se você acha que Tom falou de forma confusa, mmm. Talvez. Eu acho que ele está no local . As situações mais confusas surgem quando ''está sendo implicitamente convertido em um VARCHAR2, como o cast('' as char(1)) is nullque é ... surpreendentemente VERDADEIRO
sehe
1
@sehe a pouco confuso para mim é selecionar 1 da dupla, onde ( '' é nulo)
Matt freake
20

Suspeito que isso faça muito mais sentido se você pensar no Oracle da maneira que os desenvolvedores anteriores provavelmente pensavam - como um back-end glorificado para um sistema de entrada de dados. Cada campo no banco de dados correspondia a um campo em um formato que um operador de entrada de dados via em sua tela. Se o operador não digitou nada em um campo, seja "data de nascimento" ou "endereço", os dados para esse campo são "desconhecidos". Não há como um operador indicar que o endereço de alguém é realmente uma sequência vazia e isso não faz muito sentido.

user67897
fonte
5
Isso só faz sentido se você assumir que todos os campos em um sistema de entrada de dados são obrigatórios. Uma não resposta a um campo não obrigatório (por exemplo, "Nome do Cão") é válida; portanto, uma string vazia ainda tem um objetivo distinto de NULL. Mesmo com essa suposição, duvido que os desenvolvedores pensassem no Oracle como um "backend glorificado para um sistema de entrada de dados", então não tenho certeza se essa resposta faz sentido.
Jared
19

A documentação do Oracle alerta os desenvolvedores para esse problema, voltando pelo menos até a versão 7.

A Oracle optou por representar NULLS pela técnica "valor impossível". Por exemplo, um NULL em um local numérico será armazenado como "menos zero", um valor impossível. Quaisquer zeros negativos resultantes de cálculos serão convertidos em zero positivo antes de serem armazenados.

A Oracle também escolheu, erroneamente, considerar a sequência VARCHAR de comprimento zero (a sequência vazia) como um valor impossível e uma opção adequada para representar NULL. Acontece que a cadeia vazia está longe de ser um valor impossível. É até a identidade sob a operação de concatenação de strings!

A documentação da Oracle avisa os desenvolvedores e desenvolvedores de bancos de dados que alguma versão futura do Oracle pode interromper essa associação entre a cadeia vazia e o NULL e interromper qualquer código que dependa dessa associação.

Existem técnicas para sinalizar NULLS que não sejam valores impossíveis, mas a Oracle não as usou.

(Estou usando a palavra "local" acima para significar a interseção de uma linha e uma coluna.)

Walter Mitty
fonte
A documentação da Oracle avisa os desenvolvedores e desenvolvedores de bancos de dados de que alguma versão futura do Oracle pode interromper essa associação entre a cadeia vazia e o NULL e interromper qualquer código que dependa dessa associação - você poderia fornecer referência para esta declaração?
Piotr Dobrogost
2

String vazia é igual a NULL, simplesmente porque é o "menor mal" quando comparada à situação em que as duas (string vazia e nula) não são iguais.

Nos idiomas em que NULL e String vazia não são iguais, é preciso sempre verificar as duas condições.

Alex Kreutznaer
fonte
Basta definir uma not nullrestrição na sua coluna e verificar apenas a sequência vazia.
Egor Skriptunoff
6
A verificação de ambas as condições é trivial: WHERE Field <> ''retorna true somente se o campo não for NULL e não estiver vazio, nos bancos de dados com comportamento ANSI para cadeias vazias.
1

De acordo com documentos oficiais 11g

Atualmente, o Oracle Database trata um valor de caractere com comprimento zero como nulo. No entanto, isso pode não continuar verdadeiro em versões futuras, e a Oracle recomenda que você não trate cadeias vazias da mesma forma que nulos.

Razões possíveis

  1. val IS NOT NULL é mais legível do que val != ''
  2. Não é necessário verificar as duas condições val != '' and val IS NOT NULL
Classificador
fonte
5
Em um banco de dados totalmente compatível com ANSI, você não precisa verificar as duas condições. val <> ''já exclui NULL. Talvez você quis dizer val = '' OR val IS NULL. Mas cadeias vazias que não se comparam como NULL são úteis !
21716 ErikE
Eu concordo com a parte da comparação.
Sorter
0

Exemplo do livro

   set serveroutput on;   
    DECLARE
    empty_varchar2 VARCHAR2(10) := '';
    empty_char CHAR(10) := '';
    BEGIN
    IF empty_varchar2 IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('empty_varchar2 is NULL');
    END IF;


    IF '' IS NULL THEN
    DBMS_OUTPUT.PUT_LINE(''''' is NULL');
    END IF;

    IF empty_char IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('empty_char is NULL');
    ELSIF empty_char IS NOT NULL THEN
    DBMS_OUTPUT.PUT_LINE('empty_char is NOT NULL');
    END IF;

    END;
zloctb
fonte
-1

Porque não tratá-lo como NULL também não é particularmente útil.

Se você cometer um erro nesta área no Oracle, geralmente notará imediatamente. No SQL Server, no entanto, ele parece funcionar, e o problema só aparece quando alguém digita uma cadeia vazia em vez de NULL (talvez de uma biblioteca cliente .net, onde nulo é diferente de "", mas você geralmente as trata da mesma forma )

Não estou dizendo que a Oracle está certa, mas parece-me que os dois lados são aproximadamente igualmente ruins.

erikkallen
fonte
2
Muito, muito mais fácil de depurar. Além disso, se você vir uma célula ou entrada vazia na tela, você sabe que os dados no banco de dados são nulos. Em outros bancos de dados onde '' <> NULL, você não pode "ver" se os dados são nulos ou '', isso leva a erros muito sorrateiros. '' = null é a opção mais segura, mesmo que não seja padrão.
Lucio M. Tato
2
“Em outros bancos de dados em que '' <> NULL, você não pode" ver "se os dados são nulos ou ''" => Geralmente, as ferramentas de banco de dados exibem os NULLs de maneira diferente das cadeias vazias. Na verdade, até o Oracle SQL Developer mostra NULLs como "(null)". Eu acho que isso é para distinguir NULL de espaço em branco, mas não está relacionado à diferença entre NULL e seqüências de caracteres vazias.
Didier L
-6

Na verdade, tive apenas dificuldades em lidar com o Oracle, incluindo valores de data e hora inválidos (não podem ser impressos, convertidos ou qualquer outra coisa, apenas olhei com a função DUMP ()) que podem ser inseridos no banco de dados, aparentemente através de algum bug. versão do cliente como uma coluna binária! Tanta coisa para proteger a integridade do banco de dados!

Manipulação do Oracle de links NULLs:

http://digitalbush.com/2007/10/27/oracle-9i-null-behavior/

http://jeffkemponoracle.com/2006/02/empty-string-andor-null.html

Cade Roux
fonte
1
valores de data e hora inválidos? Não tenho certeza o que isso significa. Você postou isso como uma pergunta aqui?
1
O problema antecedeu o stackoverflow - não obtive informações úteis dos fóruns da Oracle e criei uma solução alternativa - rastreará minhas anotações e postarei aqui.
Cade Roux
Postado detalhes como uma pergunta aqui.
Cade Roux
-6

Antes de tudo, as cadeias nula e nula nem sempre foram tratadas da mesma forma pelo Oracle. Uma cadeia nula é, por definição, uma cadeia que não contém caracteres. Isso não é o mesmo que um nulo. NULL é, por definição, a ausência de dados.

Há cinco ou seis anos, a cadeia nula foi tratada de forma diferente da nula pela Oracle. Enquanto, como nulo, a cadeia nula era igual a tudo e diferente de tudo (o que acho bom para nula, mas totalmente ERRADA para a cadeia nula), pelo menos o comprimento (cadeia nula) retornaria 0, como deveria, pois a cadeia nula é uma cadeia de comprimento zero.

Atualmente no Oracle, length (null) retorna null, o que eu acho que está bem, mas length (null string) também retorna null, que é totalmente ERRADO.

Não entendo por que eles decidiram começar a tratar esses 2 "valores" distintos da mesma forma. Eles significam coisas diferentes e o programador deve ter a capacidade de agir de cada um de maneiras diferentes. O fato de terem mudado sua metodologia me diz que realmente não têm idéia de como esses valores devem ser tratados.

Michael T. Gunderson
fonte
Citação necessária para fazer uma distinção entre "cadeia nula" e valor NULL. Em qualquer banco de dados, exceto Oracle, um VARCHARcampo pode ter um valor (zero ou mais caracteres) ou nenhum valor (NULL), ponto final.
"Cinco ou seis anos atrás" a partir de 2011 cairia no período de 10g (10.1 lançado em 2003, 10.2 em 2005). 10g absolutamente não introduziu nenhuma mudança global no tratamento de nulos, e nunca houve nenhuma distinção entre NULLe uma cadeia de valor nula, e essa distinção não faz sentido. Receio que esta resposta seja uma fantasia completa.
William Robertson