sql >> Base de Datos >  >> RDS >> Mysql

ENUM (Enumeración) Tipo de datos en MySQL:12 datos principales y consejos útiles

Los datos MySQL ENUM son un tipo de datos de cadena con un valor elegido de la lista de valores permitidos. Establece estos valores permitidos durante la creación de la tabla como se muestra a continuación:

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'
);

Fácil, ¿no?

Para empezar, la validación de datos es instantánea sin otra tabla y una clave externa. En el modo de servidor estricto, esto significa que no puede forzar una entrada incorrecta. ¡Esto es genial!

¿O lo es?

Como cualquier otra cosa en el mundo, no siempre es un felices para siempre.

Después de leer los siguientes 12 datos clave sobre MySQL ENUM, puede decidir si es bueno para su próxima base de datos o tabla en MySQL.

Para este artículo, la versión de MySQL es 8.0.23 y el motor de almacenamiento es InnoDB.

1. MySQL ENUM es un tipo de par clave/valor de cadena

MySQL ENUM es un par clave/valor. Los valores son cadenas y las claves son números de índice.

Pero, ¿dónde está el índice?

MySQL asigna automáticamente números a medida que aparecen en su lista. Entonces, ya sea que se trate de una lista corta de colores, tipos de clientes, saludos o métodos de pago, se asignarán números. Esa es una lista fija que nunca se expandirá. Piense en 20 o menos elementos y valores que nunca tendrán más atributos. De lo contrario, necesitas una mesa.

Pero, ¿cómo se numeran estos índices?

2. El índice ENUM de MySQL comienza con 1 pero puede ser NULL o cero

Comenzaré con un ejemplo.

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() 
);

Aquí hay 2 valores ENUM de MySQL: géneropaís . Permítanme comenzar con el género columna que contiene 2 valores:Masculino y Mujer . El índice para Hombre es 1 y mujer es 2. Esto significa que los índices clave comienzan con 1.

A partir de este sencillo ejemplo, puede identificar el índice para el país columna. Tiene 12 valores. Comienza con los Estados Unidos con un índice de 1 y termina con Nueva Zelanda con un índice de 12.

Nota :este índice no se refiere a los índices de tablas que usamos para búsquedas rápidas.

Además de estos números del 1 al 65.535, las columnas ENUM también pueden ser NULL o cero. En nuestro ejemplo, el país la columna acepta NULL. Entonces, además de los índices 1 a 12, NULL es otro posible índice con un valor NULL.

También puede tener un índice 0. Esto sucede en las siguientes situaciones:

  • El modo de servidor para su MySQL no es estricto.
  • Insertas un valor que no está en la lista de valores permitidos.
  • Entonces, la inserción tendrá éxito, pero el valor es una cadena vacía con un índice de cero.

Para evitar errores, utilice siempre un modo de servidor estricto.

3. MySQL ENUM limita los valores posibles en una columna

En modo estricto, el país columna en nuestro ejemplo anterior solo aceptará 12 valores posibles. Entonces, si intenta hacer esto, aparecerá el error "Datos truncados para la columna 'país'":

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

El siguiente mensaje de error ocurrió porque Corea del Sur no está en la lista enumerada.

El mensaje de error es el mismo que en MySQL Workbench.

Si el servidor MySQL utilizado aquí distingue entre mayúsculas y minúsculas, tampoco se aceptará:

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

¿Por qué? Definimos el género como Masculino , no MASCULINO . Y el país es Estados Unidos , no estados unidos.

Al final, los valores enumerados en el tipo de datos MySQL ENUM actúan como restricciones de clave externa pero sin otra tabla.

Aparte de esto, hay otro beneficio que brindan los datos ENUM de MySQL.

4. Salida amigable sin el uso de JOIN

No hay necesidad de JOIN, pero la salida es amigable. Tomemos el siguiente ejemplo de ENUM en MySQL para explicarlo:

SELECT * FROM people 
WHERE country = 4;

Esta consulta recuperará personas del Reino Unido. De manera predeterminada, verá las cadenas que definió en la columna ENUM. Pero internamente, los índices numerados se almacenan. Aquí está el resultado:

Nota :Los datos que ves se generaron usando dbForge Studio para la herramienta de generación de datos de MySQL. Generé 50.000 nombres usando la herramienta.

Mientras tanto, se puede lograr el mismo resultado cuando se usa una tabla separada y una unión.

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;

Entonces, ¿debería usar MySQL ENUM para evitar JOIN por completo? ¡Definitivamente no! Esto es bueno para una lista pequeña pero fija. Más datos con un número indefinido de filas y más atributos requieren una tabla. Y para hacer una salida más amigable como en la Figura 2, también necesitará un JOIN. Tener una tabla separada es más flexible y no requiere nada del desarrollador cuando los datos están activos. Este no es el caso con Enumdatatype.

5. Filtrar la enumeración de MySQL por índice o valor de cadena

En el punto #4, vio un ejemplo con una cláusula WHERE para filtrar con una columna ENUM. Usó el índice para especificar el país. Entonces, esto también funcionará:

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

También puede usar el valor de cadena, como el siguiente:

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

6. La clasificación es por índice

La clasificación puede ser un poco complicada. Los valores ENUM se almacenan según sus números de índice, no el valor. Consulte el código a continuación y el resultado que sigue en la Figura 3.

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

Si desea que la clasificación se base en el valor, convierta la columna en un CHAR, como el que se muestra a continuación.

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

¿Qué tal esto?

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

Por lo que parece, el valor se utilizará para ordenar. Pero ese no es el caso. El resultado será el mismo que en la Figura 3. ORDER BY con CAST es la mejor manera de ordenar por valor.

7. Almacenamiento ENUM de MySQL es de hasta 2 bytes solamente

De acuerdo con la documentación oficial, el almacenamiento predeterminado de MySQL ENUM involucra el index. La tabla resultante es más compacta en comparación con el almacenamiento de valores. Un (1) byte para enumeraciones con 1 a 255 valores posibles. Dos (2) bytes para 256 a 65 535 valores posibles.

Pero hay un secreto que quiero contarte.

Por supuesto, cuando se trata de almacenamiento, los valores ocuparán más que el índice. Dado que el diseño adecuado de la mesa produce un espacio de almacenamiento más pequeño, creemos otra mesa con una mesa de país separada.

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() 
);

Ahora, insertemos los mismos datos.

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;

Para hacer eso, usamos la tabla INFORMACION_ESQUEMA.TABLAS. Vea el código a continuación:

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;

Una tabla normalizada sin columnas ENUM en comparación con una tabla con ella requiere el mismo tamaño en bytes. Ambos tienen 50.000 registros con los mismos nombres utilizando el motor de almacenamiento InnoDB. Pero claro, el nuevo país la mesa también ocupará espacio. Debe sopesar las otras ventajas y desventajas de usar ENUM.

8. MySQL ENUM es solo para cadenas literales

MySQL ENUM solo acepta literales de cadena. Entonces, el siguiente código no funcionará:

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

La función CONCAT dentro de Enumdatatype no está permitida así como otras expresiones SQL válidas.

9. MySQL ENUM no se puede reutilizar

Desde este punto, verá el lado oscuro de MySQL ENUM.

Primero, no puedes reutilizarlo. Tendrá que duplicar las mismas enumeraciones de color, tamaño y prioridad si las necesita en otra tabla. Un diseño como el de la Figura 6 a continuación es imposible con ENUM.

Para usar ENUM en las 2 tablas anteriores, debe duplicar la lista de prioridades en las 2 tablas.

10. Agregar más valores requiere modificar la tabla

En el género lista anterior, tratamos de usar solo 2 elementos:Masculino y Mujer . ¿Qué sucede si su empresa decide adoptar la comunidad LGBTQ? Debe ejecutar ALTER TABLE y agregar al final de la enumeración Lesbian , gay , bisexuales , Transgénero y Queer . Aquí está el código:

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

Ejecutar esto en mi computadora portátil con 50,000 registros solo tomó menos de un segundo. Las tablas más grandes y complejas consumirán un poco más de tiempo. Si la lista de género es una tabla, todo lo que necesita es insertar los 5 valores nuevos.

Cambiar el nombre de un valor también necesitará ALTER TABLE. Una tabla separada solo requiere una sencilla instrucción UPDATE.

11. No puede enumerar fácilmente los valores posibles

¿Rellena listas desplegables o botones de radio agrupados desde una tabla? Es fácil cuando tienes una mesa de campo. Haga un SELECT id , nombre del país DE país y ya está listo para completar la lista desplegable.

Pero, ¿cómo harás esto con MySQL ENUM?

Primero, obtenga la información de la columna de la tabla INFORMACION_ESQUEMA.COLUMNAS, así:

/* 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';

Luego, debe analizar esa cadena y formatearla antes de completar una lista desplegable. Bastante arcaico, ¿no?

Pero hay una última cosa.

12. MySQL ENUM no es estándar

ENUM es una extensión de MySQL para el estándar ANSI SQL. Otros productos RDBMS no admiten esto. Por lo tanto, consulte el tutorial de MySQL apropiado antes de comenzar sus proyectos. Si necesita portar su base de datos MySQL llena de ENUM a SQL Server, por ejemplo, necesita hacer una solución alternativa. Las soluciones variarán según cómo diseñe la tabla de destino en SQL Server.

resultado

Debe sopesar los pros y los contras de usar MySQL ENUM. Tener una tabla separada con la normalización adecuada aplicada es lo más flexible en un futuro incierto.

Damos la bienvenida a puntos adicionales. Entonces, diríjase a la sección de Comentarios a continuación y cuéntenos al respecto. También puede compartir esto en sus plataformas de redes sociales favoritas.