Mysql
 sql >> Base de données >  >> RDS >> Mysql

Type de données ENUM (énumération) dans MySQL :12 principaux faits et conseils utiles

Les données MySQL ENUM sont un type de données chaîne avec une valeur choisie dans la liste des valeurs autorisées. Vous définissez ces valeurs autorisées lors de la création de la table comme indiqué ci-dessous :

CREATE TABLE Product
(
    id int NOT NULL PRIMARY KEY,
    productName varchar(30) NOT NULL,
    color enum('blue','red','yellow','black','white') NOT NULL DEFAULT 'blue'
);

Facile, n'est-ce pas ?

Pour commencer, la validation des données est instantanée sans autre table ni clé étrangère. En mode serveur strict, cela signifie que vous ne pouvez pas forcer une mauvaise entrée. C'est génial !

Ou est-ce ?

Comme toute autre chose dans le monde, ce n'est pas toujours un bonheur pour toujours.

Après avoir lu les 12 faits clés suivants sur MySQL ENUM, vous pouvez décider s'il convient à votre prochaine base de données ou table dans MySQL.

Pour cet article, la version MySQL est 8.0.23 et le moteur de stockage est InnoDB.

1. MySQL ENUM est un type de paire clé/valeur de chaîne

MySQL ENUM est une paire clé/valeur. Les valeurs sont des chaînes et les clés sont des numéros d'index.

Mais où est l'index ?

MySQL attribue automatiquement les numéros tels qu'ils apparaissent sur votre liste. Ainsi, qu'il s'agisse d'une liste restreinte de couleurs, de types de clients, de salutations ou de méthodes de paiement, des numéros seront attribués. C'est une liste fixe qui ne s'allongera jamais. Pensez à 20 éléments ou moins et à des valeurs qui n'auront jamais d'autres attributs. Sinon, il vous faut une table.

Mais comment ces index sont-ils numérotés ?

2. L'index MySQL ENUM commence par 1 mais peut être NULL ou zéro

Je vais commencer par un exemple.

CREATE TABLE people
(
  id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
  lastname varchar(30) NOT NULL,
  firstname varchar(30) NOT NULL,
  middlename varchar(30) NOT NULL,
  gender enum('Male','Female') NOT NULL DEFAULT 'Female',
  country enum('United States', 'Canada', 'Brazil', 
               'United Kingdom','Poland','Ukraine', 'Lithuania',  
               'Japan','Philippines','Thailand', 'Australia','New Zealand')  
              DEFAULT 'United States',
  modifieddate datetime NOT NULL DEFAULT NOW() 
);

Il y a 2 valeurs MySQL ENUM ici : sexe et pays . Permettez-moi de commencer par le sexe colonne contenant 2 valeurs :Homme et Femme . L'index pour Masculin est 1, et Femme est 2. Cela signifie que les index de clé commencent par 1.

À partir de cet exemple simple, vous pouvez identifier l'index du pays colonne. Il a 12 valeurs. Cela commence par les États-Unis avec un indice de 1 et se termine par la Nouvelle-Zélande avec un indice de 12.

Remarque :cet index ne fait pas référence aux index de table que nous utilisons pour les recherches rapides.

Outre ces nombres de 1 à 65 535, les colonnes ENUM peuvent également être NULL ou zéro. Dans notre exemple, le pays la colonne accepte NULL. Ainsi, à part les index 1 à 12, NULL est un autre index possible avec une valeur NULL.

Vous pouvez également avoir un index 0. Cela se produit dans les situations suivantes :

  • Le mode serveur de votre MySQL n'est pas strict.
  • Vous insérez une valeur qui ne figure pas dans la liste des valeurs autorisées.
  • Ensuite, l'insertion réussira, mais la valeur est une chaîne vide avec un index de zéro.

Pour éviter les erreurs, utilisez toujours un mode serveur strict.

3. MySQL ENUM limite les valeurs possibles dans une colonne

En mode strict, le pays colonne dans notre exemple précédent n'acceptera que 12 valeurs possibles. Donc, si vous essayez de le faire, l'erreur "Données tronquées pour la colonne 'pays'" sera générée :

INSERT INTO people (lastname, firstname, middlename, gender, country)
  VALUES ('Choi', 'Seungcheol', '','Male','South Korea');

Le message d'erreur ci-dessous s'est produit car la Corée du Sud ne figure pas sur la liste énumérée.

Le message d'erreur est le même que dans MySQL Workbench.

Si le serveur MySQL utilisé ici est sensible à la casse, cela ne sera pas accepté non plus :

INSERT INTO people (lastname, firstname, middlename, gender, country)
  VALUES ('Hemsworth', 'Chris', '', 'MALE', 'united states');

Pourquoi? Nous avons défini le genre comme Masculin , pas MALE . Et le pays est États-Unis , pas États-Unis.

Au final, les valeurs énumérées dans le type de données MySQL ENUM agissent comme des contraintes de clé étrangère mais sans autre table.

En plus de cela, les données MySQL ENUM offrent un autre avantage.

4. Sortie conviviale sans l'utilisation de JOIN

Pas besoin de JOIN, mais la sortie est conviviale. Prenons l'exemple ENUM ci-dessous dans MySQL pour l'expliquer :

SELECT * FROM people 
WHERE country = 4;

Cette requête récupérera les personnes du Royaume-Uni. Par défaut, vous voyez les chaînes que vous avez définies dans la colonne ENUM. Mais en interne, les index numérotés sont stockés. Voici le résultat :

Remarque  :Les données que vous voyez ont été générées à l'aide de dbForge Studio pour l'outil de génération de données de MySQL. J'ai généré 50 000 noms à l'aide de l'outil.

Pendant ce temps, le même résultat peut être obtenu en utilisant une table séparée et une jointure.

SELECT
 p.id
,p.lastname
,p.firstname
,p.middlename
,CASE WHEN p.gender = 'M' THEN 'Male' ELSE 'Female' END AS gender
,c.countryname AS country
,p.modifieddate
FROM people_no_enums p
LEFT JOIN country c ON p.country = c.id
WHERE p.country = 4;

Alors, devriez-vous utiliser MySQL ENUM pour éviter complètement les JOIN ? Définitivement pas! C'est bon pour une liste petite mais fixe. Plus de données avec un nombre indéfini de lignes et plus d'attributs nécessitent une table. Et pour rendre une sortie plus conviviale comme dans la figure 2, vous aurez également besoin d'un JOIN. Avoir une table séparée est plus flexible et ne nécessite rien de la part du développeur lorsque les données sont en direct. Ce n'est pas le cas avec Enumdatatype.

5. Filtrer l'énumération MySQL par index ou valeur de chaîne

Au point #4, vous avez vu un exemple avec une clause WHERE à filtrer avec une colonne ENUM. Il a utilisé l'index pour spécifier le pays. Donc, cela fonctionnera aussi :

SELECT * from people
WHERE country IN (1,3,5)
AND gender = 1;

Vous pouvez également utiliser la valeur de chaîne, comme celle ci-dessous :

SELECT * FROM people 
WHERE country='Philippines'
AND gender = 'Female';

6. Le tri est par index

Le tri peut être un peu délicat. Les valeurs ENUM sont stockées en fonction de leurs numéros d'index, et non de la valeur. Découvrez le code ci-dessous et la sortie qui suit dans la figure 3.

SELECT DISTINCT 
 country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY country;

Si vous souhaitez que le tri soit basé sur la valeur, convertissez la colonne en CHAR, comme celui ci-dessous.

SELECT DISTINCT 
 country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY CAST(country AS char);

Et ça ?

SELECT DISTINCT 
 country AS CountryName
,country + 0 AS CountryId
FROM people
ORDER BY CountryName;

À première vue, la valeur sera utilisée pour le tri. Mais ce n'est pas le cas. La sortie sera la même que dans la figure 3. ORDER BY avec un CAST est le meilleur moyen de trier par valeur.

7. Stockage MySQL ENUM est jusqu'à 2 octets seulement

Selon la documentation officielle, le stockage par défaut MySQL ENUM implique l'index. La table résultante est plus compacte par rapport au stockage des valeurs. Un (1) octet pour les énumérations avec 1 à 255 valeurs possibles. Deux (2) octets pour 256 à 65 535 valeurs possibles.

Mais il y a un secret que je veux vous dire.

Bien sûr, lorsqu'il s'agit de stockage, les valeurs occuperont plus que l'index. Étant donné qu'une conception de table appropriée produit une empreinte de stockage plus petite, créons une autre table avec une table de pays distincte.

CREATE TABLE country
(
   id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
   countryname varchar(30) NOT NULL,
   modifieddate datetime DEFAULT NOW()
);

CREATE TABLE people_no_enums
(
  id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
  lastname varchar(30) NOT NULL,
  firstname varchar(30) NOT NULL,
  middlename varchar(30) NOT NULL,
  gender char(1) not NULL,
  country tinyint DEFAULT 1,
  modifieddate datetime NOT NULL DEFAULT NOW() 
);

Maintenant, insérons les mêmes données.

INSERT INTO country (id, countryname, modifieddate)
  VALUES (1, 'United States', NOW()), (2, 'Canada', NOW()), (3, 'Brazil', NOW()), 
         (4, 'United Kingdom', NOW()), (5, 'Poland', NOW()), (6, 'Ukraine', NOW()), 
         (7, 'Lithuania', NOW()), (8, 'Japan', NOW()), (9, 'Philippines', NOW()), 
         (10, 'Thailand', NOW()), (11, 'Australia', NOW()), 
         (12, 'New Zealand', NOW());

INSERT INTO people_no_enums
SELECT
 p.id
,p.lastname
,p.firstname
,p.middlename
,CASE WHEN p.gender = 1 THEN 'M' ELSE 'F' END AS gender
,c.id
,p.modifieddate
FROM people p
LEFT JOIN country c ON p.country = c.countryname;

Pour ce faire, nous utilisons la table INFORMATION_SCHEMA.TABLES. Voir le code ci-dessous :

SELECT
table_name,
ROUND(((data_length + index_length)), 2) AS "Size in Bytes"
FROM information_schema.TABLES
WHERE table_schema = "testenumsdb"
AND TABLE_NAME LIKE 'people%'
ORDER BY (data_length + index_length) DESC;

Une table normalisée sans colonnes ENUM par rapport à une table avec elle nécessite la même taille en octets. Les deux ont 50 000 enregistrements du même nom en utilisant le moteur de stockage InnoDB. Mais bien sûr, le nouveau pays la table occupera également de l'espace. Vous devez peser les autres avantages et inconvénients de l'utilisation d'ENUM.

8. MySQL ENUM est pour les littéraux de chaîne uniquement

MySQL ENUM n'accepte que les littéraux de chaîne. Ainsi, le code ci-dessous ne fonctionnera pas :

CREATE TABLE Product
(
   id int NOT NULL PRIMARY KEY,
   productName varchar(30),
   color enum('red','orange',CONCAT('red','orange'))
);

La fonction CONCAT à l'intérieur du Enumdatatype n'est pas autorisée ainsi que d'autres expressions SQL valides.

9. MySQL ENUM ne peut pas être réutilisé

À partir de là, vous verrez le côté obscur de MySQL ENUM.

Premièrement, vous ne pouvez pas le réutiliser. Vous devrez dupliquer les mêmes énumérations de couleur, de taille et de priorité si vous en avez besoin dans une autre table. Une conception comme celle de la figure 6 ci-dessous est impossible avec les ENUM.

Pour utiliser ENUM dans les 2 tables ci-dessus, vous devez dupliquer la liste des priorités sur les 2 tables.

10. Ajouter plus de valeurs nécessite de modifier le tableau

Dans le genre liste précédente, nous avons essayé d'utiliser 2 éléments uniquement :Masculin et Femme . Et si votre entreprise décidait d'embrasser les LGBTQ ? Vous devez exécuter un ALTER TABLE et ajouter à la fin de l'énumération Lesbian , gay , Bisexuel , Transgenre , et Queer . Voici le code :

ALTER TABLE people
   MODIFY COLUMN gender     
          enum('Male','Female','Lesbian','Gay','Bisexual','Transgender','Queer')     
          NOT NULL DEFAULT 'Male';

L'exécuter sur mon ordinateur portable avec 50 000 enregistrements n'a pris que moins d'une seconde. Des tables plus grandes et plus complexes prendront un peu plus de temps. Si la liste des sexes est un tableau, il vous suffit d'insérer les 5 nouvelles valeurs.

Renommer une valeur nécessitera également ALTER TABLE. Une table séparée ne nécessite qu'une instruction UPDATE simple.

11. Vous ne pouvez pas facilement répertorier les valeurs possibles

Remplissez-vous des listes déroulantes ou des boutons radio groupés à partir d'un tableau ? C'est facile quand on a une table country. Faites un SELECT id , nom du pays DE pays , et vous êtes prêt à remplir la liste déroulante.

Mais comment ferez-vous cela avec MySQL ENUM ?

Tout d'abord, récupérez les informations de colonne de la table INFORMATION_SCHEMA.COLUMNS, comme ceci :

/* Get the possible values for country ENUM. */
SELECT  
 TABLE_NAME
,COLUMN_NAME
,COLUMN_TYPE
FROM information_schema.columns
WHERE TABLE_SCHEMA='testenumsdb'
  AND TABLE_NAME = 'people'
  AND COLUMN_NAME = 'country';

Ensuite, vous devez analyser cette chaîne et la formater avant de remplir une liste déroulante. Assez archaïque, n'est-ce pas ?

Mais il y a une dernière chose.

12. MySQL ENUM n'est pas standard

ENUM est une extension MySQL de la norme ANSI SQL. Les autres produits RDBMS ne le prennent pas en charge. Alors, référez-vous au tutoriel MySQL approprié avant de commencer vos projets. Si vous avez besoin de transférer votre base de données MySQL pleine d'ENUM vers SQL Server, par exemple, vous devez faire une solution de contournement. Les solutions de contournement varient en fonction de la manière dont vous concevez la table cible dans SQL Server.

Résultat

Vous devez peser le pour et le contre de l'utilisation de MySQL ENUM. Avoir une table séparée avec une normalisation appropriée appliquée est le plus flexible dans un avenir incertain.

Nous accueillons des points supplémentaires. Alors, rendez-vous dans la section Commentaires ci-dessous et parlez-nous-en. Vous pouvez également le partager sur vos plateformes de médias sociaux préférées.