Stocker un bool avec un enum, c’est mal.

Avec MySQL, stocker un booléen (0 ou 1) dans un type enum (plutôt que dans un type numérique comme le ferait toute personne saine d’esprit), est une très mauvaise idée, qui fera à coup sûr perdre quelques heures au développeur qui devra maintenir le code. Et voici pourquoi.

Disons que la table qui a été créée ressemble à ça :

create table enum_is_evil (
  id integer not null auto_increment,
  value enum('0','1') not null default '0',
  primary key (id)
);

insert into enum_is_evil (value) values ('0'), ('0'), ('1');

Si on ne fait pas gaffe qu’il s’agit d’un enum et pas d’un type numérique (comme on pourrait logiquement le supposer), voila ce que ça donne…

mysql> select * from enum_is_evil where value = 0;
Empty set (0.00 sec)

Bon, aucun résultat alors qu’on devrait en avoir 2… Essayons autre chose.

mysql> select * from enum_is_evil where value = 1;
+----+-------+
| id | value |
+----+-------+
|  1 | 0     |
|  2 | 0     |
+----+-------+
2 rows in set (0.00 sec)

Youpi ! C’est n’importe quoi !

Et voyons ce qui se passe quand on ne fait pas attention à l’insertion, c’est encore plus drole.

insert into enum_is_evil (value) values (0), (0), (1);

Note : cette requête produit des warnings (logique), mais lorsqu’elle est executée dans un script, il n’y aucune chance de s’en apercevoir.

mysql> select * from enum_is_evil where value = 0;
+----+-------+
| id | value |
+----+-------+
|  4 |       |
|  5 |       |
+----+-------+
2 rows in set (0.00 sec)

Yeah, des valeurs vides dans la table alors qu’on devrait avoir uniquement des 0 ou des 1 !

mysql> select * from enum_is_evil where value = 1;
+----+-------+
| id | value |
+----+-------+
|  1 | 0     |
|  2 | 0     |
|  6 | 0     |
+----+-------+
3 rows in set (0.00 sec)

Encore mieux, la valeur “1” qu’on a ajoutée est devenue un “0” !

Conclusion : bien que tout ça soit logique quand on lit la doc du type ENUM (il suffit d’ajouter des quotes autour des valeurs pour obtenir les bons résultats), c’est une source d’erreur potentielle assez vicieuse quand on s’attend à travailler avec un type numérique. Utilisez plutôt un TINYINT !

2 thoughts on “Stocker un bool avec un enum, c’est mal.

  1. Moi

    Un simple
    enum(‘non’,’oui’) ou enum(‘no’,’yes’)
    résoudrait ton problème
    et rendrait le code plus clair,
    sans perte de performance :)

  2. Rémi

    Moui pourquoi pas, mais je suis pas convaincu. C’est vrai que ça devrait éviter le risque de mettre 0 ou 1 sans quotes dans les requêtes et de se louper, mais néanmoins ça pose toujours des problèmes :

    (1) Si, par habitude, tu saisis 0 ou 1 sans quotes ça va foirer comme décrit dans l’article, parce que 0 sera la valeur vide et 1 sera “non”.

    (2) C’est plus lisible oui, mais ce n’est pas international :-) Bon d’accord, c’est un peu tiré par les cheveux, mais au moins 0 ou 1 ça fonctionne pour tous les développeurs du monde, et puis c’est quand même clair.

    Pourquoi vouloir absolument un enum ?

Comments are closed.