web-dev-qa-db-fra.com

SQL: chaîne vide vs valeur NULL

Je sais que ce sujet est un peu controversé et il y a beaucoup d'articles/opinions divers sur Internet. Malheureusement, la plupart d'entre eux supposent que la personne ne sait pas quelle est la différence entre NULL et une chaîne vide. Ils racontent donc des histoires de résultats surprenants avec les jointures/agrégats et donnent généralement des leçons SQL un peu plus avancées. En faisant cela, ils manquent absolument de tout et sont donc inutiles pour moi. J'espère donc que cette question et toutes les réponses feront avancer un peu le sujet.

Supposons que j'ai un tableau avec des informations personnelles (nom, naissance, etc.) où l'une des colonnes est une adresse e-mail de type varchar. Nous supposons que pour une raison quelconque, certaines personnes pourraient ne pas vouloir fournir une adresse e-mail. Lors de l'insertion de ces données (sans e-mail) dans le tableau, deux choix sont disponibles: définir la cellule sur NULL ou la définir sur une chaîne vide (''). Supposons que je connais toutes les implications techniques du choix d'une solution plutôt qu'une autre et que je peux créer des requêtes SQL correctes pour l'un ou l'autre scénario. Le problème est que même lorsque les deux valeurs diffèrent au niveau technique, elles sont exactement les mêmes au niveau logique. Après avoir regardé NULL et '' je suis arrivé à une seule conclusion: je ne connais pas l'adresse e-mail du gars. Aussi peu importe mes efforts, je n'ai pas pu envoyer d'e-mail en utilisant une chaîne NULL ou vide, donc apparemment la plupart des serveurs SMTP sont d'accord avec ma logique. J'ai donc tendance à utiliser NULL où je ne connais pas la valeur et considère la chaîne vide comme une mauvaise chose.

Après quelques discussions intenses avec des collègues, je suis venu avec deux questions:

  1. ai-je raison de supposer que l'utilisation d'une chaîne vide pour une valeur inconnue fait "mentir" une base de données sur les faits? Pour être plus précis: en utilisant l'idée de SQL de ce qui est de la valeur et de ce qui ne l'est pas, je pourrais conclure: nous avons une adresse e-mail, juste en découvrant qu'elle n'est pas nulle. Mais plus tard, lorsque j'essaierai d'envoyer un e-mail, j'arriverai à une conclusion contradictoire: non, nous n'avons pas d'adresse e-mail, cette base de données @! # $ Devait mentir!

  2. Existe-t-il un scénario logique dans lequel une chaîne vide '' pourrait être un si bon vecteur d'informations importantes (à part la valeur et aucune valeur), qui serait gênant/inefficace à stocker par tout autre moyen (comme une colonne supplémentaire). J'ai vu de nombreux articles affirmer qu'il est parfois bon d'utiliser une chaîne vide avec des valeurs réelles et des valeurs NULL, mais jusqu'à présent, je n'ai pas vu de scénario logique (en termes de conception SQL/DB).

P.S. Certaines personnes seront tentées de répondre que ce n'est qu'une question de goût personnel. Je ne suis pas d'accord. Pour moi, c'est une décision de conception avec des conséquences importantes. Je voudrais donc voir les réponses où l'opinion à ce sujet est étayée par des raisons logiques et/ou techniques.

73
Jacek Prucia

Je dirais que NULL est le bon choix pour "pas d'adresse e-mail". Il existe de nombreuses adresses e-mail "non valides" et "" (chaîne vide) n'en est qu'une. Par exemple, "foo" n'est pas une adresse e-mail valide, "a @ b @ c" n'est pas valide et ainsi de suite. Donc, juste parce que "" n'est pas une adresse e-mail valide, il n'y a aucune raison de l'utiliser comme valeur "sans adresse e-mail".

Je pense que vous avez raison de dire que "" n'est pas la bonne façon de dire "Je n'ai pas de valeur pour cette colonne". "" est une valeur.

Un exemple où "" pourrait être une valeur valide, séparée de NULL pourrait être le deuxième prénom d'une personne. Tout le monde n'a pas de deuxième prénom, vous devez donc faire la différence entre "pas de deuxième prénom" ("" - chaîne vide) et "je ne sais pas si cette personne a un deuxième prénom ou non" (NULL ). Il existe probablement de nombreux autres exemples où une chaîne vide est toujours une valeur valide pour une colonne.

84
Dean Harding

Tout en étant d'accord avec les commentaires ci-dessus, j'ajouterais cet argument comme motivation principale:

  1. Il est évident pour tout programmeur qui regarde une base de données qu'un champ marqué NULL est un champ facultatif. (c'est-à-dire que l'enregistrement ne nécessite pas de données pour cette colonne)
  2. Si vous marquez un champ NON NUL, tout programmeur doit présumer intuitivement qu'il s'agit d'un champ obligatoire.
  3. Dans un champ qui autorise les valeurs NULL, les programmeurs doivent s'attendre à voir des valeurs Null plutôt que des chaînes vides.

Pour des raisons de codage intuitif auto-documenté, utilisez NULL au lieu de chaînes vides.

41
colinbashbash

Dans votre exemple, s'il s'agit d'une valeur provenant directement du champ Web, j'utiliserais une chaîne vide. Si l'utilisateur pouvait spécifier qu'il ne voulait pas fournir de courrier électronique, ou pouvait le supprimer - alors NULL.

Voici un lien avec des points que vous pourriez considérer: https://stackoverflow.com/questions/405909/null-vs-empty-when-dealing-with-user-input/405945#405945

--- édité (En réponse au commentaire de Thomas) ---

Les bases de données ne vivent pas sans les applications qui les utilisent. La définition de NULL ou '' n'a aucune valeur, si l'application ne peut pas l'utiliser correctement.

Prenons un exemple où l'utilisateur remplit un formulaire LONG et appuyez sur Entrée, qui enverra une demande persistante au serveur. Il pourrait être en train d'entrer son e-mail. Très probablement, vous voulez stocker tout ce qu'il a dans le champ e-mail, afin qu'il puisse le terminer plus tard. Et s'il n'entre qu'un seul caractère? Que se passe-t-il s'il entre un caractère et le supprime? Lorsque l'e-mail n'est pas requis, les utilisateurs souhaitent parfois le supprimer: le moyen le plus simple de simplement effacer le champ. Dans le cas où un e-mail n'est pas requis, il convient de le valider avant l'envoi.

Autre exemple: l'utilisateur fournit un e-mail en tant que spam à @ [bigcompany] .com - dans ce cas, il n'est pas nécessaire d'envoyer un e-mail, même s'il existe et est valide (et peut même exister). L'envoi d'un tel peut être bon marché, mais s'il y a 10 000 utilisateurs avec de tels e-mails pour les abonnements quotidiens, une telle validation peut gagner beaucoup de temps.

6

Utilisez Null.

Il ne sert à rien de stocker une valeur de '', alors que le simple fait de rendre le champ dans la table nullable fera l'affaire. Cela rend également les requêtes plus évidentes.

Quelle requête SQL est la plus évidente et la plus lisible si vous souhaitez trouver des utilisateurs avec une adresse e-mail?

  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

Je dirais que 2 est. Bien que 3 soit plus robuste dans les cas où de mauvaises données sont stockées.

Pour le cas de l'adresse e-mail du formulaire, qui est facultative, elle doit également figurer dans le tableau. En SQL, c'est un champ nullable, ce qui signifie qu'il n'est pas connu.

Je ne peux pas penser à une valeur commerciale raisonnable dans le stockage d'une chaîne vide dans une table autre que simplement une mauvaise conception. C'est comme stocker une valeur de chaîne 'NULL' ou 'BLANK', et avoir des développeurs supposons qu'il est nul ou une chaîne vide. Pour moi, c'est une mauvaise conception. Pourquoi stocker cela quand il y a NULL ??

Utilisez simplement NULL et vous rendrez tout le monde un peu plus heureux.

PLUS D'INFO:

SQL utilise un système logique à trois valeurs: vrai, faux et inconnu.

Pour une explication meilleure et plus détaillée, je recommande aux développeurs de lire: Requêtes SQL - au-delà de VRAI et FAUX .

5
spong

Malheureusement, Oracle a confondu la représentation de la chaîne VARCHAR de longueur zéro avec la représentation de NULL. Ils sont tous deux représentés en interne par un seul octet de valeur zéro. Cela rend la discussion d'autant plus difficile.

Une grande partie de la confusion autour de NULL est autour de logique à trois valeurs. Considérez le pseudocode suivant:

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

Vous ne vous attendriez pas au troisième message, mais c'est ce que vous obtiendriez, selon trois logiques valorisées. Trois logiques valorisées conduisent les gens vers de nombreux bugs.

Une autre source de confusion est de tirer des conclusions de l'absence de données, comme de tirer une conclusion du chien qui n'a pas aboyé pendant la nuit. Souvent, ces inférences n'étaient pas ce que l'auteur du NULL avait l'intention de transmettre.

Cela dit, il existe de nombreuses situations où NULL gère très bien l'absence de données et produit exactement les résultats souhaités. Un exemple est les clés étrangères dans les relations facultatives. Si vous utilisez un NULL pour indiquer aucune relation dans une ligne donnée, cette ligne sera supprimée d'une jointure interne, comme vous vous y attendriez.

Sachez également que même si vous évitez complètement NULLS dans les données stockées (sixième forme normale), si vous effectuez des jointures externes, vous devrez toujours faire face à NULLS.

5
Walter Mitty

Je pense que la réponse de Dean Hardings couvre très bien cela. Cela dit, je voudrais mentionner que lorsque vous parlez de NULL par rapport aux chaînes vides au niveau de la base de données, vous devriez avoir une réflexion sur vos autres types de données. Souhaitez-vous stocker la date minimale lorsqu'aucune date n'est fournie? ou -1 quand aucun int n'est fourni? Le stockage d'une valeur lorsque vous n'avez aucune valeur signifie que vous devez alors garder une trace de toute une gamme de valeurs non. Au moins un pour chaque type de données (peut-être plus lorsque vous obtenez des cas où -1 est une valeur réelle, vous devez donc avoir une alternative, etc.). Si vous avez besoin/voulez faire quelque chose de "flou" au niveau de l'application, c'est une chose mais il n'est pas nécessaire de polluer vos données.

5
bendemes

pour la question technique spécifique, le problème n'est pas nul vs chaîne vide, c'est un échec de validation. Une chaîne vide n'est pas une adresse e-mail valide!

pour la question philosophique, la réponse est similaire: validez vos entrées. Si une chaîne vide est une valeur valide pour le champ en question, attendez-la et codez-la; sinon, utilisez null.

Une chaîne vide serait une entrée valide pour répondre à la question: Qu'est-ce que le mime a dit à la girafe?

3
Steven A. Lowe

Je pourrais penser à une raison pour avoir NULL et la chaîne vide:

  • Vous avez des adresses e-mail valides: [email protected]
  • Vous n'en avez pas (et vous devriez probablement en demander un): NULL
  • Vous savez que cette personne n'a pas d'adresse e-mail: Empty String.

Cependant, je ne recommanderais pas cela et utiliserais un champ séparé pour demander si vous savez qu'aucun n'existe.

2
Marcel

La question que je comprends, est de savoir quelles interprétations de NULL et de chaîne vide doivent être choisies. Cela dépend du nombre états dans lequel le champ particulier peut être.

L'interprétation dépend de la façon dont la base de données est accessible. S'il y a une couche dans le code qui résume complètement la base de données, alors choisir une politique (y compris à deux coulmn) qui fonctionne est tout à fait acceptable. (Il est cependant important de documenter clairement la politique). Cependant, si la base de données est accessible à plusieurs endroits, vous devez utiliser un schéma très simple, car le code sera plus difficile à maintenir et peut être erroné dans ce cas.

1
apoorv020

Eh bien, fondamentalement, au niveau logique, il n'y a pas de différence entre une valeur "non valide" et "aucune entrée utilisateur", ce sont tous des "cas spéciaux" la plupart du temps. Cas d'erreur.

Avoir null prend de l'espace supplémentaire: ceil (colonnes_avec_null/8) en octets/par ligne.

La cellule vide et la valeur nulle sont les deux façons de marquer que quelque chose ne va pas/devrait être par défaut. Pourquoi auriez-vous besoin de 2 "mauvais" états? Pourquoi utiliser des valeurs NULL si elles prennent plus d'espace et signifient exactement la même chose que des chaînes vides? Cela ne fera qu'introduire de la confusion et de la redondance lorsque vous aurez deux choses qui signifient (cela pourrait signifier) ​​exactement la même chose, il est facile d'oublier que vous devez utiliser des valeurs NULL au lieu de chaînes vides (si, par exemple, l'utilisateur a omis certains champs).

Et vos données peuvent devenir un gâchis. Dans un monde parfait, vous diriez "les données seront toujours correctes et je m'en souviendrai" ... mais quand les gens doivent travailler en équipe et que tout le monde n'est pas exactement à votre niveau, il n'est pas rare de voir OERE (aa. xx <> '' ET bb.zz IS NOT NULL)

Donc, au lieu de corriger les membres de mon équipe tous les deux jours, j'applique simplement une règle simple. Aucune valeur nulle, JAMAIS!

Le comptage des valeurs NON NULL est plus rapide ... une question simple est de savoir pourquoi auriez-vous besoin de faire cela?

1
Slawek

J'ai tendance à le voir non pas du point de vue DB mais du point de vue du programme. Je sais que cette question concerne le clic SQL, mais vraiment, combien d'utilisateurs accèdent directement aux données?

Dans un programme, je n'aime pas null/rien. Il y a quelques exceptions, mais ce n'est que cela. Et ces exceptions sont vraiment de mauvaises implémentations.

Donc, si l'utilisateur n'a pas mis l'e-mail, il devrait y avoir quelque chose qui détermine si cela est valide ou non. Si un e-mail vierge convient, il affiche une chaîne vide. Si l'utilisateur n'a pas envoyé d'e-mail et que cela viole une règle, l'objet doit l'indiquer.

L'idée que null ait un sens est de la vieille école et c'est quelque chose que les programmeurs modernes doivent contourner.

Même dans la conception de la base de données, pourquoi le champ de messagerie ne peut-il pas autoriser les valeurs nulles et avoir une chaîne de longueur nulle et avoir un autre champ indiquant si l'utilisateur a entré quelque chose? Faut-il demander un peu à un SGBD? La base de données ne devrait, à mon avis, ni gérer la logique métier ni la logique d'affichage. Il n'a pas été construit pour cela et fait donc un très mauvais travail de manipulation.

1
ElGringoGrande