Quel type de données MySQL utiliser pour stocker des valeurs booléennes

1208

Puisque MySQL ne semble pas avoir de type de données «booléen», quel type de données abusez-vous pour stocker des informations vraies / fausses dans MySQL?

Surtout dans le cadre de l'écriture et de la lecture de / vers un script PHP.

Au fil du temps, j'ai utilisé et vu plusieurs approches:

  • tinyint, champs varchar contenant les valeurs 0/1,
  • champs varchar contenant les chaînes '0' / '1' ou 'true' / 'false'
  • et enfin énumérer les champs contenant les deux options «vrai» / «faux».

Rien de ce qui précède ne semble optimal. J'ai tendance à préférer la variante tinyint 0/1, car la conversion automatique de type en PHP me donne des valeurs booléennes assez simplement.

Alors, quel type de données utilisez-vous? Existe-t-il un type conçu pour les valeurs booléennes que j'ai négligé? Voyez-vous des avantages / inconvénients en utilisant un type ou un autre?

Peter Mortensen
la source
217
Quiconque lit les anciennes réponses à cette question doit comprendre que MySQL a ajouté un type de données un peu dans la version 5. Utilisez ces informations comme vous le pouvez. dev.mysql.com/doc/refman/5.0/en/bit-type.html
smp7d
7
pour la version actuelle du type booléen MYSQL est disponible - dev.mysql.com/doc/refman/5.5/en/numeric-type-overview.html vérifier cela. selon cette valeur zéro considéré comme faux
DevT
7
bit(1)est un peu ** à importer dans Excel. Passer aux tinyint(1)travaux.
Cees Timmerman le
8
maintenant nous avons booléen après 5 ans
V-SHY

Réponses:

1232

Pour MySQL 5.0.3 et supérieur, vous pouvez utiliser BIT. Le manuel dit:

Depuis MySQL 5.0.3, le type de données BIT est utilisé pour stocker les valeurs de champ binaire. Un type de BIT (M) permet le stockage de valeurs M bits. M peut aller de 1 à 64.

Sinon, selon le manuel MySQL, vous pouvez utiliser bool et boolean qui sont actuellement des alias de tinyint (1):

Bool, Boolean: ces types sont synonymes de TINYINT (1). Une valeur de zéro est considérée comme fausse. Les valeurs non nulles sont considérées comme vraies.

MySQL déclare également que:

Nous avons l'intention d'implémenter la gestion de type booléen complet, conformément au SQL standard, dans une future version de MySQL.

Références: http://dev.mysql.com/doc/refman/5.5/en/numeric-type-overview.html

Markus
la source
11
Ouais, je choisirais ceci ou, pour un CHAR (1) et je stockerais 'Y' / 'N' ou 'T' / 'F' etc. selon le contexte. L'avantage d'utiliser un petit type entier est que vous obtenez une portabilité maximale entre les SGBDR
Roland Bouman
36
Opter pour char, en PHP au moins, conduira à plus de code, car !$booleanil ne sera jamais évalué correctement sans traitement supplémentaire.
Mild Fuzz
10
@Pecerier Rien que vous ne pouviez pas google, mais ok, je vais mordre. Tout d'abord, jetez un œil à data0type.h. Veuillez noter que innodb ne définit pas de manière native un type BIT. S'il traitait les champs BIT de la manière que vous décrivez, nous trouverions sûrement un indice de son existence là-bas. Deuxièmement, lisez mysqlperformanceblog.com/2008/04/23/… . Et n'hésitez pas à nous expliquer quels clients MySQL incroyables dans le "marktetplace" jouent bien avec les champs BIT. Ils seront utiles pour quiconque a manqué cet article sans aucun doute.
Roland Bouman
9
Lorsque je fais une sélection dans les champs de bits du client de ligne de commande mysql standard, il apparaît complètement vide. Pour cette raison, je préfère TINYINT (1).
Utilisateur
8
@MikePurcell Je déteste demander mais pourquoi voudriez-vous auto_incrementune colonne représentant une valeur booléenne?
Chris Hayes
248

BOOLet BOOLEANsont synonymes de TINYINT(1). Zéro false, tout le reste true. Plus d'informations ici .

Philip Morton
la source
7
Le (1)ne fait rien de plus que de déterminer comment la valeur est affichée, si vous êtes conscient de la taille du stockage, vous souhaitez utiliser à la BITplace
JamesHalsall
35
@JamesHalsall: En fait, BIT(1)et TINYINT(1)utiliseront tous les deux un octet de stockage. Jusqu'à MySQL 5.0.3, BITétait en fait synonyme de TINYINT. Les versions ultérieures de MySQL ont changé l'implémentation de BIT. Mais même avec le changement d'implémentation, il n'y a toujours aucun avantage de "taille de stockage" pour le BITtype de données (au moins avec InnoDB et MyISAM; d'autres moteurs de stockage, par exemple NDB, peuvent avoir une optimisation de stockage pour plusieurs déclarations de colonnes BIT.) Le plus gros problème est que certains clients les bibliothèques ne reconnaissent pas ou ne gèrent pas correctement les BITcolonnes de type de données renvoyées . Un TINYINTfonctionne mieux.
spencer7593
5
Le manuel MySQL 5.0 indique clairement qu'une valeur booléenne est 1 ou 0. L'expression "toute autre chose true" n'est pas vraie.
Walter
7
@Walter: C'est en fait un peu vrai, l'explication manque quelque peu. En bref, dans un contexte booléen, une expression peut être évaluée à NULL, FALSE ou TRUE. Dans une instruction MySQL, une expression évaluée dans un contexte booléen est d'abord évaluée sous forme d'entier (les valeurs décimales et flottantes sont arrondies, les chaînes sont converties de la manière inhabituelle habituelle MySQL convertit les chaînes en entier). Un NULL est évidemment NULL (ni VRAI ni FAUX). Une valeur entière de 0 est traitée comme FALSE et toute autre valeur entière (1, 2, -7, etc.) est évaluée à TRUE. Pour des raisons de compatibilité, nous imitons cette logique / gestion de TINYINT booléen
spencer7593
4
@Walter: C'est facile à tester, par exemple SELECT 'foo' AS bar FROM dual WHERE -7. L'expression -7 est évaluée dans un contexte booléen et la requête renvoie une ligne. Nous pouvons tester avec 0, ou n'importe quelle expression qui évalue à la valeur entière 0, et aucune ligne n'est retournée. Si l'expression dans la clause WHERE est évaluée à n'importe quelle valeur entière non nulle autre que zéro, l'expression est TRUE. (Je crois que les valeurs décimales et flottantes sont "arrondies" à un entier, par exemple, WHERE 1/3évaluées à WHERE 0. Nous obtenons le même résultat avec WHERE 'foo', car la chaîne est 'foo'également évaluée à la valeur entière 0.
spencer7593
71

C'est une solution élégante que j'apprécie tout à fait car elle utilise zéro octet de données:

some_flag CHAR(0) DEFAULT NULL

Pour le définir sur true, définissez some_flag = ''et pour le définir sur false, définissez some_flag = NULL.

Ensuite, pour tester true, vérifiez si some_flag IS NOT NULLet pour tester false, vérifiez if some_flag IS NULL.

(Cette méthode est décrite dans «MySQL hautes performances: optimisation, sauvegardes, réplication, etc.» par Jon Warren Lentz, Baron Schwartz et Arjen Lentz.)

RS
la source
3
astuce de fantaisie! cela est utile si vous travaillez avec MySQL <5 et peut-être même une empreinte plus légère que le BIT, mais dans un effort pour respecter la convention et un peu moins de frais de calcul (logique vs valeur exacte), je dirais que le BIT est la meilleure façon de procéder.
zamnuts
59
Cela peut être «rapide», mais il obscurcit les données de sorte que tout nouveau développeur n'aurait aucune idée de ce que représente la colonne.
Richthofen
5
Ceci utilise la même quantité d'octets que le BIT (1)
ITS Alaska
25
Bonne chance pour obtenir un ORM qui correspond bien à cela.
Craig Labenz
4
Je suis d'accord avec @Richthofen et j'ai du mal à imaginer une situation dans laquelle je recommanderais jamais d'utiliser cette solution. Cependant, si elle doit être utilisée, le fait de spécifier un COMMENTdans la définition de la colonne qui NULLindique faux et ''indique vrai pourrait contribuer très peu à faciliter la compréhension future.
eggyal
34

Si vous utilisez le type BOOLEAN, celui-ci a pour alias TINYINT (1). C'est mieux si vous voulez utiliser du SQL standardisé et que cela ne vous dérange pas que le champ puisse contenir une valeur hors limites (fondamentalement tout ce qui n'est pas 0 sera «vrai»).

ENUM ('False', 'True') vous permettra d'utiliser les chaînes dans votre SQL, et MySQL stockera le champ en interne sous la forme d'un entier où 'False' = 0 et 'True' = 1 en fonction de l'ordre dans lequel l'énumération est spécifiée .

Dans MySQL 5+, vous pouvez utiliser un champ BIT (1) pour indiquer un type numérique à 1 bit. Je ne pense pas que cela utilise réellement moins d'espace dans le stockage, mais vous permet à nouveau de contraindre les valeurs possibles à 1 ou 0.

Tout ce qui précède utilisera environ la même quantité de stockage, il est donc préférable de choisir celui avec lequel vous trouvez le plus facile à travailler.

Ciaran McNulty
la source
8
Votre remarque concernant l'ENUM n'est pas vraie: essayez CAST (yourenumcol AS UNSIGNED) et vous remarquerez que False sera 1 et True sera 2. Un autre problème avec ENUM est qu'il est trop facile d'insérer '' (chaîne vide ). Je déconseille d'utiliser cela.
Roland Bouman
4
D'après mon expérience, l'utilisation d'un champ BIT (1) à partir du code PHP était un peu gênant. TINYINT (1) était beaucoup plus facile et produisait un code plus lisible.
M-Peror
1
@ M-Peror - "l'utilisation d'un champ BIT (1) à partir du code PHP était un peu gênant" ... sans jeu de mots. :) Mais, oui, je suis d'accord. Je me souviens que TINYINT (1) était aussi plus facile ... je ne me souviens plus pourquoi. Quelqu'un d'autre a des réflexions à ce sujet? BIT (1) semble plus agréable à première vue car vous pouvez limiter à 0 ou 1. Je pense que BIT a parfois été interprété comme des données binaires (selon le langage de programmation et le pilote / bibliothèque); tandis que TINYINT a été traité plus comme un nombre.
BMiner
2
@BMiner - haha, c'était vraiment involontaire, je n'ai pas remarqué ça :) utiliser dans une expression (booléenne).
M-Peror
34

Cette question a reçu une réponse, mais je pensais que je mettrais mes 0,02 $. J'utilise souvent un CHAR(0), où '' == true and NULL == false.

Depuis les documents mysql :

CHAR(0)est également très agréable lorsque vous avez besoin d'une colonne qui ne peut prendre que deux valeurs: Une colonne qui est définie comme CHAR(0) NULLn'occupe qu'un seul bit et ne peut prendre que les valeurs NULLet ''(la chaîne vide).

Josh
la source
16
mm, cela semble demander des ennuis si vous comme moi. Je veux dire, selon la langue, il peut être trop facile de ne pas repérer la différence entre NULL et '' (par exemple PHP).
Roland Bouman
3
En termes d'économie d'espace (le nombre d'octets utilisés pour représenter un booléen), cette approche est clairement gagnante. Cela enregistre un octet sur TINYINT. L'inconvénient (comme le soulignent certains commentaires) est que certains clients peuvent avoir des difficultés à distinguer entre une chaîne NULL et une chaîne vide. Même certaines bases de données relationnelles (par exemple Oracle) ne font pas de distinction entre une chaîne de longueur nulle et une chaîne NULL.
spencer7593
3
C'est très intelligent! J'avais l'habitude d'écrire du code intelligent, maintenant je l'évite comme la peste. Je veux maintenant que mon code ait une intention claire, pas seulement un comportement correct. Mon conseil? Ne faites cela que si vous souhaitez confondre toute personne devant prendre en charge le code / la base de données. Par exemple, en PHP à la fois ''et nullsont des valeurs fausses.
CJ Dennis
1
@CJDennis Si vous avez résumé votre couche de base de données derrière le modèle de référentiel, vous n'avez pas à vous soucier de l'obscurité de cette solution.
prograhammer
17

Bit n'est avantageux sur les différentes options d'octets (tinyint, enum, char (1)) que si vous avez beaucoup de champs booléens. Un champ de bits occupe toujours un octet complet. Deux champs de bits correspondent à ce même octet. Trois, quatre, cinq, six, sept, huit. Après quoi, ils commencent à remplir l'octet suivant. En fin de compte, les économies sont si faibles qu'il y a des milliers d'autres optimisations sur lesquelles vous devriez vous concentrer. À moins que vous n'ayez à traiter une énorme quantité de données, ces quelques octets n'apporteront pas grand-chose. Si vous utilisez Bit avec PHP, vous devez transtyper les valeurs entrant et sortant.

Thor
la source
1
+1 pour le commentaire de transtypage. Pour ajouter à cela lorsque vous travaillez avec des langages de programmation, évitez d'utiliser des techniques de programmation paresseuse au profit de la cohérence. Utilisez des opérateurs identiques au lieu de simplement égaux. Dans le cas de PHP, if ($ var == "") sera vrai pour 0, faux, nul, non défini et "". pour tester toutes les valeurs, il est souvent préférable d'utiliser if (true === empty ($ var)) car cela évitera également les erreurs non définies. Vous devez également valider le type de données avec lequel vous travaillez si (is_int ($ var) && $ var === 0) ou le transtyper pour le forcer à devenir un type de données (int) $ var spécifique pour la tâche.
fyrye
@Thor est-ce vrai pour MySQL dans la même mesure que pour MSSQL? Je migre une nouvelle application qui n'est pas encore entrée en production de MSSQL vers MySQL. Je n'utilise pas PHP mais plutôt la conversion de C # en Java 8. Étant donné que Java est un langage fortement typé, je ne suis pas préoccupé par la gestion des types ... juste tous les drapeaux de bits qui passeraient d'un octet jusqu'à 8 drapeaux à 1 octet pour chaque indicateur donné TINYINT (1). Connaissez-vous une documentation sur ce sujet pour MySQL?
Zack Jannsen
1
@Thor En faisant des recherches plus approfondies, il est clair quelle devrait être la réponse. Des changements se produisent et nous avons constaté des améliorations dans cette gestion. Connaissez votre langue qui se trouvera dans la couche Application / couche d'accès aux données et connaissez la prise en charge de vos bibliothèques. J'utilise actuellement Java et BIT (1) est le choix recommandé pour le moment pour des bibliothèques comme Hybernate et l'utilisation de JDBC. Voici l'URL [Voir tableau 5.2]: dev.mysql.com/doc/connector-j/en/…
Zack Jannsen
12

Jusqu'à ce que MySQL implémente un type de données bit, si votre traitement est vraiment pressé pour l'espace et / ou le temps, comme avec des transactions à volume élevé, créez un champ TINYINT appelé bit_flagspour toutes vos variables booléennes, et masquez et déplacez le bit booléen que vous désirez dans votre SQL requete.

Par exemple, si votre bit le plus à gauche représente votre champ booléen et les 7 bits les plus à droite ne représentent rien, votre bit_flagschamp sera égal à 128 (binaire 10000000). Masquez (masquez) les sept bits les plus à droite (à l'aide de l'opérateur au niveau du bit &) et déplacez le 8e bit de sept espaces vers la droite, pour finir avec 00000001. Maintenant, le nombre entier (qui, dans ce cas, est 1) est votre valeur.

SELECT (t.bit_flags & 128) >> 7 AS myBool FROM myTable t;

if bit_flags = 128 ==> 1 (true)
if bit_flags = 0 ==> 0 (false)

Vous pouvez exécuter des instructions comme celles-ci pendant que vous testez

SELECT (128 & 128) >> 7;

SELECT (0 & 128) >> 7;

etc.

Puisque vous avez 8 bits, vous avez potentiellement 8 variables booléennes d'un octet. Certains futurs programmeurs utiliseront invariablement les sept bits suivants, vous devez donc masquer. Ne vous contentez pas de changer, ou vous créerez l'enfer pour vous et les autres à l'avenir. Assurez-vous que MySQL fait votre masquage et votre déplacement - ce sera beaucoup plus rapide que de le faire avec le langage de script Web (PHP, ASP, etc.). Assurez-vous également de placer un commentaire dans le champ de commentaire MySQL de votre bit_flagschamp.

Vous trouverez ces sites utiles lors de la mise en œuvre de cette méthode:

Jonathan
la source
7
Cela semble être un moyen affreux d'obscurcir l'intention des futurs programmeurs. Bien sûr, cela semble être beaucoup de mal d'économiser 7 octets (en supposant que vous utilisez les 8 bools dans cette seule table!)
yep
@yep il n'y a pas du tout d'obscurcissement! Écrivez la documentation et les commentaires MySQL expliquant chaque champ du tableau (comme le mentionne la réponse)! La stratégie de démasquage MySQL suggérée semble solide et stocker jusqu'à 16 champs booléens différents avec seulement quelques colonnes est mieux que d'en avoir 16 à la place. S'il est trop déroutant d'utiliser la manipulation de bits et que vous préférez utiliser votre langage de script Web pour obtenir chaque booléen, stockez-le simplement en tant que VARCHARet effectuez la procédure de démasquage dans le code (vous n'avez pas non plus besoin de le limiter à 8 champs) ...
CPHPython
Le BITtype existe. Voir dev.mysql.com/doc/refman/8.0/en/bit-type.html
dolmen
10

J'en ai eu marre d'essayer d'obtenir des zéros, des NULLS et '' d'arrondir avec précision une boucle de valeurs PHP, MySql et POST, donc j'utilise simplement 'Oui' et 'Non'.

Cela fonctionne parfaitement et ne nécessite aucun traitement spécial qui n'est pas évident et facile à faire.

Geoff Kendall
la source
17
Si vous vouliez vraiment perdre autant d'espace et compromettre les performances, vous auriez au moins pu faire CHAR (1) avec les options Y et N.
ILikeTacos
3
Dans la plupart des situations du monde réel, il y a une réelle différence entre un «non» et une simple absence d'information. Par exemple, vous souhaiterez peut-être cocher une case par défaut si un utilisateur n'a pas encore dit «non». Exactement combien d'espace pensez-vous que vous économisez, et combien de traitement effectuez-vous chaque fois que vous avez besoin de faire la distinction entre un faux et un NULL - si en effet vous pouvez même distinguer? Dans un monde d'images stockées et de vidéo numérique, le bit ou deux d'économie d'espace est totalement hors de propos, mais la clarté et le traitement réduit est réel.
Geoff Kendall
8
Cette réponse n'est pas fausse car elle fonctionnera et elle n'est pas aussi mauvaise que les gens l'attribuent. Pour la plupart des projets (c'est-à-dire: tailles de table <1mil de lignes) Les différences de performances entre les solutions fournies seront négociables. Je ne me plaindrai pas si mes requêtes reviennent dans 7 vs 5 millisecondes ... Pour être honnête, cependant, si vos tables grandissent dans les lignes de 10 mil ou plus, ce n'est probablement pas la solution préférée.
Brad
1
+1 de ma part pour l'utilisation du type de données ENUM. Personnellement, je préfère cette notation: ENUM ('y', 'n'). Il est compact (juste un octet de long), intuitif et beau en tant que convention au niveau de l'application pour tous les drapeaux booléens. Vous pouvez l'utiliser directement avec des champs de formulaire HTML. par exemple avec PHP: <select name = "production"> <option value = "y" <? = $ production === 'y'? 'selected = "selected"': ''? >> Oui </option> <option value = "n" <? = $ production === 'n'? 'selected = "selected"': ''? >> No </option> </select>
Vlado
2
Lol, cela a attiré mon attention mais je dois dire que @GeoffKendall a raison. Dans une tonne de cas, il n'y a pas besoin de performances optimales et quelle que soit la méthode qui fait le travail pour vous, c'est la bonne méthode.
Madmenyo
6

En se référant à ce lien de type de données booléen dans Mysql , selon l'utilisation de l'application, si l'on veut que seulement 0 ou 1 soit stocké, le bit (1) est le meilleur choix.

Vidz
la source
6
Il est vrai que BIT(1)seul un b'0'ou une b'1'valeur sera stockée. Le plus gros problème avec le BITtype de données est que diverses bibliothèques clientes ont une variété de manipulations louches du type de données. Découvrez le comportement de divers outils SQL (SQLyog, TOAD for MySQL, SQL Developer), des outils qui «désossent» les modèles de base de données et divers clients, comme JDBC, PHP, Perl DBI, et pour faire bonne mesure, testez quelques cadres ORM ( Hibernate, Mybatis, JPA). En termes de facilité d'utilisation, la compatibilité outil / framework / support natif TINYINT(1)est clairement gagnante.
spencer7593
Oui. Il se termine dépend du cadre envisagé pour l'application. Par exemple, le framework Phalcon de PHP ne gère pas le type de données Bit
Vidz
Pour mémoire, MyBatis prend en charge à la fois BITet TINYINT. Référez-vous à la classe JdbcType de MyBatis, mybatis.org/mybatis-3/apidocs/reference/org/apache/ibatis/type/…
Lucky
1
@Vidz Je vous donne plus un pour la mention de BIT (1) mais je voudrais également signaler aux développeurs qui lisent ceci - Connaissez votre langue qui sera dans la couche Application / couche d'accès aux données et connaissez le support de vos bibliothèques. J'utilise actuellement Java et BIT (1) est le choix recommandé pour le moment pour des bibliothèques comme Hybernate et l'utilisation de JDBC. Voici l'URL [Voir tableau 5.2]: dev.mysql.com/doc/connector-j/en/…
Zack Jannsen
6

Puisque MySQL (8.0.16) et MariaDB (10.2.1) ont tous deux implémenté la contrainte CHECK, j'utiliserais maintenant

bool_val TINYINT CHECK(bool_val IN(0,1))

Vous ne serez en mesure de stocker 0, 1ou NULL, ainsi que les valeurs qui peuvent être convertis en 0ou 1sans erreurs comme '1', 0x00, b'1'ou TRUE/ FALSE.

Si vous ne souhaitez pas autoriser les valeurs NULL, ajoutez l' NOT NULLoption

bool_val TINYINT NOT NULL CHECK(bool_val IN(0,1))

Notez qu'il n'y a pratiquement aucune différence si vous utilisez TINYINT, TINYINT(1)ou TINYINT(123).

Si vous souhaitez que votre schéma soit compatible vers le haut, vous pouvez également utiliser BOOLouBOOLEAN

bool_val BOOL CHECK(bool_val IN(TRUE,FALSE))

démo db <> violon

Paul Spiegel
la source
qu'en est-il d'énum (0, 1)
santiago arizti
3
@santiagoarizti ENUM(ça doit être enum('0', '1')- note: ce sont des cordes) n'est pas une bonne idée. Il y a trop de problèmes en raison de la façon dont il est stocké en interne et de la façon dont les valeurs non-chaîne sont traitées. Par exemple. 0et FALSE ne peut pas être stocké. 1et TRUEdevenir '0'. Et 2devient '1'.
Paul Spiegel
Meilleure réponse ... pour ceux qui utilisent MySQL 8+
dolmen
2

Après avoir lu les réponses ici, j'ai décidé d'utiliser bit(1)et oui, c'est en quelque sorte mieux dans l'espace / temps, MAIS après un certain temps j'ai changé d'avis et je ne l'utiliserai plus jamais. Cela a beaucoup compliqué mon développement, lors de l'utilisation d'instructions préparées, de bibliothèques, etc. (php).

Depuis lors, j'utilise toujours tinyint(1), semble assez bon.

Lémures
la source
3
Vous voulez expliquer en quoi cela a compliqué votre développement?
Chazy Chaz
@ChazyChaz, il attend vrai / faux au lieu de 1/0, contrairement à certains autres dbs comme SQL Server. Cela peut parfois conduire à des situations étranges où vous pensez que vous le définissez sur vrai, mais cela ne se produit pas réellement.
maembe
0

Vous pouvez utiliser le type de données BOOL, BOOLEAN pour stocker des valeurs booléennes.

Ces types sont synonymes de TINYINT (1)

Cependant, le type de données BIT (1) a plus de sens pour stocker une valeur booléenne (soit vrai [1] ou faux [0]) mais TINYINT (1) est plus facile à utiliser lorsque vous sortez les données, interrogez, etc. sur et pour réaliser l'interopérabilité entre MySQL et d'autres bases de données. Vous pouvez également vérifier cette réponse ou ce fil .

MySQL convertit également les types de données BOOL, BOOLEAN en TINYINT (1).

De plus, lisez la documentation

Premkumar chalmeti
la source