Stocker un booléen dans MySQL

J’ai vu pas mal de méthodes pour stocker un booléen dans SQL. Certaines sont vraiment à éviter, d’autres sont plus faciles, etc. Voici mon (humble) avis sur celles à absolument éviter et les bonnes méthodes.

!!!!Méthode 1: Stocker comme ENUM(‘0′,’1’) Probablement la plus mauvaise idée que vous pouvez avoir. Je m’arrache les cheveux à chaque fois que je vois ça dans le projet sur lequel je bosse actuellement (et dont je n’ai pas fait la conception). Petite explication du pourquoi du comment. Soit une table membre, avec un champ `valide` de type ENUM(‘0′,’1’), représentant si le membre a validé son inscription ou non. Je veux savoir si le membre est validé : /// SELECT id,nom FROM membre WHERE id=666 AND valide=1; (0 row(s)returned) /// => pas d’erreur, mais ne renvoie rien. Bizarre, j’ai pourtant cru que c’était bon. Je vérifie : /// SELECT id,nom FROM membre WHERE id=666 AND valide=0; (0 row(s)returned) /// => pas d’erreur, mais toujours rien retourné. Damned! En effet, MySQL ne fait pas de typecasting, et pour lui, ‘0’ ne vaut ni 1 ni 0. Deuxième soucis, c’est si vous utilisez des fonctions de comparaison MySQL. Exemple : /// select if (valide,’ok’,’pas bon’) FROM membre WHERE id=666; /// => retourne ‘ok’, quelque soit la valeur de valide. En effet, une chaine de caractère, même ‘0’, est toujours vraie. !!!Côté stockage Chaque valeur ENUM est associée à un index. Manque de bol, la 1e valeur a l’index 1. Donc ENUM(‘0′,’1’) donne les index ‘0’ => 1 et ‘1’ => 2. Génial… L’index 0 est utilisé pour stocker une chaîne vide (cas d’erreur). [cf la doc MySQL.|http://dev.mysql.com/doc/refman/5.0/fr/enum.html|fr] Enfin, pour ceux qui me parlent de performance, sachez qu’un ENUM prend un ou deux octets en fonction du nombre de valeurs. Et si mes souvenirs sont bons, ENUM prend toujours 2 octets dans d’anciennes versions de MySQL  »(à vérifier). »%%% __Conclusion__ : on oublie. Note : ENUM() a également les mêmes soucis que VARCHAR(), donc n’utilisez pas de stockage de chaine pour cela, point barre. !!!!Méthode 2: Stocker comme un entier ( »INTEGER »). C’est une bonne solution, reste à choisir quel type de champ. Il en existe beaucoup : TINYINT, BIGINT, etc. Leur différence ? Ils permettent de stocker des entiers plus ou moins grand. Comme nous voulons juste stocker 2 valeurs, autant prendre le moins couteux, à savoir TINYINT, qui ne prend qu’un seul octet en mémoire. En définissant votre champ sur TINYINT(1), vous limitez même les erreurs. Pour les curieux qui veulent savoir l’espace de stockage nécéssaire et l’intervalle de chaque type de colonne,[ la documentation est là pour ça.|http://dev.mysql.com/doc/refman/5.0/fr/numeric-types.html|fr] !!!!Méthode 3: Stocker comme un champ de type BIT(1) Solution relativement récente (BIT a été intégré dans MySQL 5.0.3). Niveau stockage c’est pas forcément très efficace, car BIT(1) prend quand même un octet. Il est question d’améliorer cette gestion dans de prochaines versions de MySQL. Par contre niveau utilisation c’est pas vraiment simple. !!!Insertion: /// INSERT INTO matable VALUES (b’1′); INSERT INTO matable VALUES (0b1); INSERT INTO matable VALUES (b’0′); INSERT INTO matable VALUES (0b0); /// !!!Pour la récupération … …, y’a une astuce. En effet,  »SELECT monchamp FROM matable » vous renverra de jolis signes cabalistique. En effet, MySQL vous renvoie la valeur binaire. Pour récupérer l’entier, plusieurs méthodes: /// SELECT monchamp+0 from test; SELECT bin(champ) from test; SELECT oct(champ) from test; SELECT hex(champ) from test; /// Attention si vous stockez plus qu’un booléen (BIT(M) avec M>1), les sélections ci-dessus auront alors des comportements différents entre elles. Comme toujours, [RTFM|http://dev.mysql.com/doc/refman/5.0/fr/bit-field-values.html|fr]. !!!!Conclusion Personnellement, je recommanderais de stocker des booléens dans un champ TINYINT(1). C’est ce qui est le plus simple à utiliser. BIT reste un peu trop complexe pour peu/aucun gain de performance.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *