Pourquoi Oracle 9i traite-t-il une chaîne vide comme NULL?

216

Je sais qu'il ne considère « » comme NULL, mais qui ne fait pas grand - chose à me dire pourquoi cela est le cas. Si je comprends bien les spécifications SQL, '' n'est pas la même chose que NULL- l'une est une donnée valide et l'autre indique l'absence de cette même information.

N'hésitez pas à spéculer, mais veuillez indiquer si c'est le cas. S'il y a quelqu'un d'Oracle qui peut le commenter, ce serait fantastique!

Chris R
la source
9
N'hésitez pas à spéculer? D'une manière ou d'une autre, je ne pense pas que cela vous fournira le meilleur ensemble de réponses ..
SCdF
1
Je suppose que non, mais je n'étais pas sûr qu'il y aurait une certitude sur le sujet, alors j'ai pensé que j'allais ouvrir les portes. Semble avoir bien fonctionné jusqu'à présent.
Chris R
Connexe: dba.stackexchange.com/q/49744/56961
AlikElzin-kilaka

Réponses:

216

Je crois que la réponse est qu'Oracle est très, très vieux.

Dans le passé, avant qu'il n'y ait un standard SQL, Oracle a décidé que les chaînes vides dans VARCHAR/ VARCHAR2colonnes étaient NULLet qu'il n'y avait qu'un sens de NULL (il existe des théoriciens relationnels qui feraient la différence entre des données qui n'ont jamais été demandées, données où la réponse existe mais n'est pas connue de l'utilisateur, données où il n'y a pas de réponse, etc. qui constituent toutes un sens NULL).

Au moment où la norme SQL est apparue et a convenu que NULLla chaîne vide était des entités distinctes, il y avait déjà des utilisateurs Oracle qui disposaient d'un code supposant que les deux étaient équivalents. Il restait donc essentiellement à Oracle la possibilité de casser le code existant, de violer la norme SQL ou d'introduire une sorte de paramètre d'initialisation qui changerait la fonctionnalité d'un nombre potentiellement important de requêtes. La violation du standard SQL (IMHO) était la moins perturbatrice de ces trois options.

Oracle a laissé ouverte la possibilité que le VARCHARtype de données change dans une future version pour adhérer à la norme SQL (c'est pourquoi tout le monde utilise VARCHAR2dans Oracle puisque le comportement de ce type de données est garanti de rester le même à l'avenir).

Justin Cave
la source
60

Tom Kyte VP d'Oracle:

Un varchar de longueur ZERO est traité comme NULL.

'' n'est pas traité comme NULL.

'' lorsqu'il est affecté à un caractère (1) devient '' (les types de caractères sont des chaînes remplies vides).

'' lorsqu'il est affecté à un varchar2 (1) devient '' qui est une chaîne de longueur nulle et une chaîne de longueur nulle est NULL dans Oracle (ce n'est pas long '')

Brian
la source
17
Wow, Tom est assez sournois. Étant donné que les questions se rapportent à une divergence flagrante par rapport à SQL92, vous penseriez qu'il serait moins percutant à ce sujet ... même s'il pourrait être fatigué de répondre.
Chris R
8
La meilleure chose à propos de Tom est que vous obtenez une réponse claire, qui indique exactement ce qu'il pense. Recherchez certains des commentaires où les gens ont utilisé du texte parler sur Ask Tom
Chris Gill
9
Mais il serait plus précis si la deuxième ligne était remplacée par «» n'est pas toujours traité comme NULL.
ypercubeᵀᴹ
2
@ypercube La citation n'est pas plus précise en changeant le mot effectivement utilisé par Tom. Si vous pensez que Tom l'a formulé de manière confuse, mmm. Peut être. Je pense qu'il est sur place . Les situations les plus confuses surgissent quand ''est en cours implicitement converti en un VARCHAR2, par exemple , cast('' as char(1)) is nullqui est ... étonnamment TRUE
sehe
1
@sehe le bit déroutant pour moi est de sélectionner 1 parmi dual où ('' est nul)
matt freake
20

Je soupçonne que cela a beaucoup plus de sens si vous pensez à Oracle comme les développeurs précédents l'ont probablement fait - en tant que backend glorifié pour un système de saisie de données. Chaque champ de la base de données correspond à un champ sous une forme qu'un opérateur de saisie de données a vu sur son écran. Si l'opérateur n'a rien saisi dans un champ, que ce soit "date de naissance" ou "adresse", les données de ce champ sont "inconnues". Il n'y a aucun moyen pour un opérateur d'indiquer que l'adresse de quelqu'un est vraiment une chaîne vide, et cela n'a pas vraiment de sens de toute façon.

user67897
la source
5
Cela n'a de sens que si vous supposez que chaque champ d'un système de saisie de données est obligatoire. Une non-réponse à un champ non obligatoire (par exemple "Nom du chien") est valide, donc une chaîne vide a toujours un objectif distinct de NULL. Même avec cette hypothèse en place, je doute que les premiers développeurs considéraient Oracle comme un "backend glorifié pour un système de saisie de données", donc je ne suis pas sûr que cette réponse ait du sens.
Jared
19

La documentation Oracle alerte les développeurs de ce problème, remontant au moins jusqu'à la version 7.

Oracle a choisi de représenter NULLS par la technique de la «valeur impossible». Par exemple, un NULL dans un emplacement numérique sera stocké comme "moins zéro", une valeur impossible. Tous les zéros négatifs résultant des calculs seront convertis en zéro positif avant d'être stockés.

Oracle a également choisi, à tort, de considérer la chaîne VARCHAR de longueur zéro (la chaîne vide) comme une valeur impossible et un choix approprié pour représenter NULL. Il s'avère que la chaîne vide est loin d'être une valeur impossible. C'est même l'identité sous l'opération de concaténation de chaînes!

La documentation Oracle avertit les concepteurs et les développeurs de bases de données qu'une future version d'Oracle pourrait rompre cette association entre la chaîne vide et NULL, et rompre tout code qui dépend de cette association.

Il existe des techniques pour signaler des valeurs NULL autres que des valeurs impossibles, mais Oracle ne les a pas utilisées.

(J'utilise le mot "emplacement" ci-dessus pour désigner l'intersection d'une ligne et d'une colonne.)

Walter Mitty
la source
La documentation Oracle avertit les concepteurs et les développeurs de bases de données qu'une future version d'Oracle pourrait rompre cette association entre la chaîne vide et NULL, et rompre tout code qui dépend de cette association - pourriez-vous fournir une référence pour cette déclaration?
Piotr Dobrogost
2

La chaîne vide est identique à NULL simplement parce que c'est le "moindre mal" par rapport à la situation où les deux (chaîne vide et null) ne sont pas identiques.

Dans les langues où NULL et String vide ne sont pas identiques, il faut toujours vérifier les deux conditions.

Alex Kreutznaer
la source
Définissez simplement une not nullcontrainte sur votre colonne et vérifiez uniquement la chaîne vide.
Egor Skriptunoff
6
La vérification des deux conditions est triviale: WHERE Field <> ''renvoie vrai uniquement si le champ n'est pas NULL et n'est pas vide, sur les bases de données avec un comportement ANSI pour les chaînes vides.
1

Selon les documents officiels de 11g

La base de données Oracle traite actuellement une valeur de caractère d'une longueur de zéro comme nulle. Toutefois, cela peut ne pas continuer à être vrai dans les versions futures, et Oracle vous recommande de ne pas traiter les chaînes vides de la même manière que les valeurs NULL.

Raisons possibles

  1. val IS NOT NULL est plus lisible que val != ''
  2. Pas besoin de vérifier les deux conditions val != '' and val IS NOT NULL
Trieur
la source
5
Dans une base de données entièrement compatible ANSI, vous n'avez pas à vérifier les deux conditions. val <> ''exclut déjà NULL. Peut-être que vous vouliez dire val = '' OR val IS NULL. Mais les chaînes vides qui ne se comparent pas comme NULL sont utiles !
ErikE
Je suis d'accord avec la partie comparaison.
Sorter
0

Exemple de livre

   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
la source
-1

Parce que ne pas le traiter comme NULL n'est pas particulièrement utile non plus.

Si vous faites une erreur dans ce domaine sur Oracle, vous le remarquerez généralement immédiatement. Dans SQL Server, cependant, cela semble fonctionner et le problème n'apparaît que lorsque quelqu'un entre une chaîne vide au lieu de NULL (peut-être à partir d'une bibliothèque cliente .net, où null est différent de "", mais vous les traitez généralement de la même manière) ).

Je ne dis pas qu'Oracle a raison, mais il me semble que les deux façons sont à peu près également mauvaises.

erikkallen
la source
2
Beaucoup, beaucoup plus facile à déboguer. De plus, si vous voyez une cellule vide ou une entrée à l'écran, vous savez que les données dans la base de données sont nulles. Dans d'autres bases de données où '' <> NULL, vous ne pouvez pas "voir" si les données sont nulles ou '', cela conduit à des bogues très sournois. '' = null c'est l'option la plus saine, même si elle n'est pas standard.
Lucio M. Tato
2
"Dans d'autres bases de données où '' <> NULL, vous ne pouvez pas" voir "si les données sont nulles ou ''” => Habituellement, les outils DB affichent les valeurs NULL différemment des chaînes vides. En fait, même Oracle SQL Developer affiche les valeurs NULL comme «(null)». Je suppose que c'est pour distinguer NULL des espaces blancs, mais cela n'a aucun rapport avec la différence entre NULL et les chaînes vides.
Didier L
-6

En effet, je n'ai eu que des difficultés à traiter avec Oracle, y compris des valeurs datetime invalides (ne peuvent pas être imprimées, converties ou quoi que ce soit, juste regardées avec la fonction DUMP ()) qui sont autorisées à être insérées dans la base de données, apparemment à travers un buggy version du client sous forme de colonne binaire! Voilà pour protéger l'intégrité de la base de données!

Gestion des liens NULL par Oracle:

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

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

Cade Roux
la source
1
valeurs d'heure de temps non valides? Je ne suis pas sûr de ce que cela veut dire. Avez-vous posté ceci comme une question ici?
1
Le problème a dépassé le stackoverflow - je n'ai reçu aucune information utile des forums Oracle et j'ai créé une solution de contournement - je vais retrouver mes notes et les poster ici.
Cade Roux
Les détails publiés sous forme de question ici.
Cade Roux
-6

Tout d'abord, les chaînes null et null n'ont pas toujours été traitées de la même manière par Oracle. Une chaîne nulle est, par définition, une chaîne ne contenant aucun caractère. Ce n'est pas du tout la même chose qu'un null. NULL est, par définition, l'absence de données.

Il y a environ cinq ou six ans, la chaîne null était traitée différemment de null par Oracle. Alors que, comme null, la chaîne null était égale à tout et différente de tout (ce qui, je pense, est bien pour null, mais totalement FAUX pour la chaîne null), au moins la longueur (chaîne null) retournerait 0, comme il se doit puisque la chaîne null est une chaîne de longueur nulle.

Actuellement dans Oracle, la longueur (null) renvoie null qui, je suppose, est OK, mais la longueur (chaîne nulle) renvoie également null qui est totalement FAUX.

Je ne comprends pas pourquoi ils ont décidé de commencer à traiter ces 2 "valeurs" distinctes de la même manière. Ils signifient des choses différentes et le programmeur devrait avoir la capacité d'agir sur chacun de différentes manières. Le fait qu'ils aient changé de méthodologie me dit qu'ils n'ont vraiment aucune idée de la façon dont ces valeurs doivent être traitées.

Michael T. Gunderson
la source
Citation requise pour faire une distinction entre "chaîne nulle" et valeur NULL. Dans n'importe quelle base de données sauf Oracle, un VARCHARchamp peut avoir une valeur (zéro ou plusieurs caractères) ou aucune valeur (NULL), point final.
«Il y a cinq ou six ans» de 2011 tomberait dans le délai de 10 g (10.1 publié en 2003, 10.2 en 2005). 10g n'a absolument pas introduit de changements globaux dans la gestion des NULLvaleurs nulles, et il n'y a jamais eu de distinction entre et une chaîne de valeur nulle, et une telle distinction n'a aucun sens. J'ai peur que cette réponse soit un fantasme complet.
William Robertson