MySQL, mieux vaut insérer NULL ou une chaîne vide?

230

J'ai un formulaire sur un site Web qui a beaucoup de domaines différents. Certains champs sont facultatifs tandis que d'autres sont obligatoires. Dans ma base de données, j'ai une table qui contient toutes ces valeurs, est-il préférable d'insérer une valeur NULL ou une chaîne vide dans les colonnes de base de données où l'utilisateur n'a pas mis de données?

roflwaffle
la source

Réponses:

220

En utilisant, NULLvous pouvez faire la distinction entre «ne mettre aucune donnée» et «mettre des données vides».

Quelques différences supplémentaires:

  • Un LENGTHde NULLest NULL, un LENGTHd'une chaîne vide est 0.

  • NULLles s sont triés avant les chaînes vides.

  • COUNT(message)comptera les chaînes vides mais pas NULLs

  • Vous pouvez rechercher une chaîne vide à l'aide d'une variable liée mais pas pour a NULL. Cette requête:

    SELECT  *
    FROM    mytable 
    WHERE   mytext = ?
    

    ne correspondra jamais à un NULLin mytext, quelle que soit la valeur que vous transmettez au client. Pour correspondre à NULLs, vous devrez utiliser une autre requête:

    SELECT  *
    FROM    mytable 
    WHERE   mytext IS NULL
    
Quassnoi
la source
3
mais lequel pensez-vous est plus rapide? 0 ou NULL ou ""
Atul Dravid
8
dans InnoDB NULL prennent moins de place
Timo Huovinen
37
Je pense que c'est une bonne réponse, mais elle ignore également totalement l'élément "meilleure pratique" de la question et se concentre uniquement sur les faits tangentiellement pertinents (ordre de tri NULL et longueur? Cela n'a pas d'importance). Sur la plupart des types de saisie de données texte, il n'y a pas de différence entre "aucune réponse" et "réponse vide", donc je pense que c'est une excellente question qui mérite une meilleure réponse.
Nick
6
Les valeurs NULL fonctionnent également très bien lorsque le champ UNIQUE est défini. Par exemple, si vous avez un champ comme Permis de conduire pour ajouter le numéro DL de la personne et que le gars ne l'a pas. Puisqu'il s'agit d'un champ unique, la première personne sans numéro de DL sera ajoutée mais pas la suivante car elle générera une erreur de contrainte unique. Donc, NULL est meilleur.
Saifur Rahman Mohsin
1
@Quassnoi ah désolé ... Je voulais dire, pourquoi est-ce une mauvaise pratique de définir le permis de conduire comme unique ...?
cedbeu
44

Une chose à considérer, si vous jamais envisagez de bases de données de commutation, est que Oracle ne supporte pas les chaînes vides . Ils sont automatiquement convertis en NULL et vous ne pouvez pas les interroger à l'aide de clauses comme WHERE somefield = ''.

Matt Solnit
la source
11
Cela me semblait incroyablement louche, même sur votre lien, alors je l'ai essayé. Champ nul, défini sur '', Oracle l'ignore. La longueur des rapports est nulle plutôt que 0. C'est tellement faux. Il doit y avoir un moyen de contourner cela. Je pense que je vais poster ceci comme une autre question.
Steve B.
1
Steve B.: voir cette question: stackoverflow.com/questions/1171196/…
Quassnoi
Merci pour la référence, bien que je ne comprenne toujours pas le raisonnement. Publié comme stackoverflow.com/questions/1268177/…
Steve B.
Cela pourrait valoir la peine de mettre à jour la réponse pour inclure des informations provenant du lien publié par Quassnoi
SamuelKDavis
7
Peoplesoft (avec Oracle DB) utilise un seul espace pour indiquer une valeur vide. Incroyablement stupide. Ils utilisent également 0,00025 pour indiquer 0 pour l'ETP car 0 n'est pas autorisé. De beaux choix ont été faits dans ce produit.
JP Duffy
9

Une chose à garder à l'esprit est que NULL pourrait rendre vos chemins de code beaucoup plus difficiles. En Python par exemple, la plupart des adaptateurs de base de données / ORM sont mappés NULLvers None.

Donc, des choses comme:

print "Hello, %(title)s %(firstname) %(lastname)!" % databaserow

pourrait entraîner "Bonjour, aucun Joe Doe!" Pour l'éviter, vous avez besoin de quelque chose comme ce code:

if databaserow.title:
    print "Hello, %(title)s %(firstname) %(lastname)!" % databaserow
else:
    print "Hello, %(firstname) %(lastname)!" % databaserow

Ce qui peut rendre les choses beaucoup plus complexes.

max
la source
25
À mon avis, abuser de votre base de données pour "corriger" des erreurs dans votre code ou le framework est une (très) mauvaise pratique de codage. Lorsqu'il n'y a pas de données, vous devez simplement insérer NULL et être cohérent dans l'utilisation de cela. Sinon, vous devez utiliser des instructions telles que: if (myString == null || myString = ""). Lorsqu'un objet n'est pas défini ou défini dans votre code, vous utilisez également NULL au lieu d'une sorte de "placeholder" (qui est une chaîne vide à mon avis).
Gertjan
5
Cela dépend beaucoup de la langue de votre choix. En Python "sinon myString:" teste None et "". Probablement principalement un problème culturel. La "mauvaise pratique" des Java Guys est l'élégance de la personne dynamique.
max
9

Mieux vaut insérer NULLpour la cohérence de votre base de données dans MySQL. Les clés étrangères peuvent être stockées sous forme de NULLchaînes vides, mais PAS.

Vous aurez des problèmes avec une chaîne vide dans les contraintes. Vous devrez peut-être insérer un faux enregistrement avec une chaîne vide unique pour satisfaire une contrainte de clé étrangère. Mauvaise pratique je suppose.

Voir aussi: Une clé étrangère peut-elle être NULL et / ou dupliquée?

micaball
la source
Le problème des contraintes m'a fait trébucher dans le passé, c'est pourquoi j'ai "+1" cette réponse.
HPWD
Mais si vous utilisez NULL, assurez-vous de ne jamais vous retrouver avec des chaînes vides. Facile à faire avec de nombreuses technologies d'interface utilisateur.
Tuntable
5

Je ne sais pas quelle serait la meilleure pratique ici, mais je me tromperais généralement en faveur de null, sauf si vous voulez que null signifie quelque chose de différent de empty-string, et que l'entrée de l'utilisateur corresponde à votre définition de chaîne vide.

Notez que je dis que VOUS devez définir comment vous voulez qu'ils soient différents. Parfois, il est logique de les avoir différents, parfois non. Sinon, choisissez-en un et respectez-le. Comme je l'ai dit, j'ai tendance à privilégier le NULL la plupart du temps.

Oh, et gardez à l'esprit que si la colonne est nulle, l'enregistrement est moins susceptible d'apparaître dans pratiquement toutes les requêtes qui sélectionnent (a une clause where, en termes SQL) en fonction de cette colonne, sauf si la sélection concerne une colonne nulle bien sûr.

Platine Azure
la source
1
... Et maintenant que je vois la réponse au-dessus de moi, je pense qu'il est sûr de dire que la différenciation habituelle dont vous vous souciez n'est pas de données par rapport à des données vides. :-)
Platinum Azure
1

Si vous utilisez plusieurs colonnes dans un index unique et qu'au moins une de ces colonnes est obligatoire (c'est-à-dire un champ de formulaire obligatoire), si vous définissez les autres colonnes de l'index sur NULL, vous pouvez vous retrouver avec des lignes dupliquées. En effet, les valeurs NULL sont ignorées dans les colonnes uniques. Dans ce cas, utilisez des chaînes vides dans les autres colonnes de l'index unique pour éviter les lignes en double.

COLONNES DANS UN INDEX UNIQUE:
(event_type_id, event_title, date, lieu, url)

EXEMPLE 1:
(1, 'BBQ', '2018-07-27', null, null)
(1, 'BBQ', '2018-07-27', null, null) // autorisé et dupliqué.

EXEMPLE 2:
(1, 'BBQ', '2018-07-27', '', '')
(1, 'BBQ', '2018-07-27', '', '') // NON autorisé car il est dupliqué.

Voici quelques codes:

CREATE TABLE `test` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `event_id` int(11) DEFAULT NULL,
  `event_title` varchar(50) DEFAULT NULL,
  `date` date DEFAULT NULL,
  `location` varchar(50) DEFAULT NULL,
  `url` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `event_id` (`event_id`,`event_title`,`date`,`location`,`url`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

Insérez maintenant ceci pour voir qu'il autorisera les lignes dupliquées:

INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`, 
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-27', NULL, NULL);

INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`, 
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-27', NULL, NULL);

Insérez maintenant ceci et vérifiez que ce n'est pas autorisé:

INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`, 
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-28', '', '');

INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`, 
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-28', '', '');

Il n'y a donc ni bien ni mal ici. C'est à vous de décider ce qui fonctionne le mieux avec les règles de votre entreprise.

João Marques
la source