¿Cómo agrego más miembros a mi columna de tipo ENUM en MySQL?

157

El manual de referencia de MySQL no proporciona un ejemplo claro sobre cómo hacer esto.

Tengo una columna de nombres de países de tipo ENUM a la que necesito agregar más países. ¿Cuál es la sintaxis correcta de MySQL para lograr esto?

Aquí está mi intento:

ALTER TABLE carmake CHANGE country country ENUM('Sweden','Malaysia');

El error que obtengo es: ERROR 1265 (01000): Data truncated for column 'country' at row 1.

La countrycolumna es la columna de tipo ENUM en la declaración anterior.

MOSTRAR CREAR SALIDA DE MESA :

mysql> SHOW CREATE TABLE carmake;
+---------+---------------------------------------------------------------------+
| Table   | Create Table
+---------+---------------------------------------------------------------------+
| carmake | CREATE TABLE `carmake` (
`carmake_id` tinyint(4) NOT NULL AUTO_INCREMENT,
`name` tinytext,
`country` enum('Japan','USA','England','Australia','Germany','France','Italy','Spain','Czech Republic','China','South Korea','India') DEFAULT NULL,
PRIMARY KEY (`carmake_id`),
KEY `name` (`name`(3))
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=latin1 |
+---------+---------------------------------------------------------------------+
1 row in set (0.00 sec)

SELECCIONE EL PAÍS DISTINTO DE LA SALIDA DE CARMAKE :

+----------------+
| country        |
+----------------+
| Italy          |
| Germany        |
| England        |
| USA            |
| France         |
| South Korea    |
| NULL           |
| Australia      |
| Spain          |
| Czech Republic |
+----------------+
Zaid
fuente

Respuestas:

135
ALTER TABLE
    `table_name`
MODIFY COLUMN
    `column_name2` enum(
        'existing_value1',
        'existing_value2',
        'new_value1',
        'new_value2'
    )
NOT NULL AFTER `column_name1`;
Pradip Chongbang
fuente
77
La mayoría de los comandos ALTER TABLE reescribirán completamente la tabla completa. ¿MySQL es lo suficientemente inteligente como para no hacer eso con enum?
John
enum es solo un entero elegante, con una representación de cadena. agregar elementos al final está bien, ya que solo agrega valores antiguos que significan. pero cambiar el orden / eliminar enumeraciones hará que esos números sean indefinidos. (ej. 1 => italia, 2 => alemania), luego se extenderá (1 => italia, 2 => alemania, 3 => sweenden).
lintabá
1
@John depende. Para MariaDB, se pueden agregar nuevos valores al final de la enumeración inplacedesde 10.3.7: mariadb.com/kb/en/library/…
Felipe Philipp
99

Tu código funciona para mí. Aquí está mi caso de prueba:

mysql> CREATE TABLE carmake (country ENUM('Canada', 'United States'));
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW CREATE TABLE carmake;
+---------+-------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                            |
+---------+-------------------------------------------------------------------------------------------------------------------------+
| carmake | CREATE TABLE `carmake` (
  `country` enum('Canada','United States') default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 |
+---------+-------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> ALTER TABLE carmake CHANGE country country ENUM('Sweden','Malaysia');
Query OK, 0 rows affected (0.53 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW CREATE TABLE carmake;
+---------+--------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                       |
+---------+--------------------------------------------------------------------------------------------------------------------+
| carmake | CREATE TABLE `carmake` (
  `country` enum('Sweden','Malaysia') default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 |
+---------+--------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

¿Qué error estás viendo?

FWIW esto también funcionaría:

ALTER TABLE carmake MODIFY COLUMN country ENUM('Sweden','Malaysia');

En realidad, recomendaría una tabla de país en lugar de una columna de enumeración. Es posible que tenga cientos de países que serían una enumeración bastante grande e incómoda.

EDITAR: Ahora que puedo ver tu mensaje de error:

ERROR 1265 (01000): Data truncated for column 'country' at row 1.

Sospecho que tiene algunos valores en la columna de su país que no aparecen en su ENUM. ¿Cuál es el resultado del siguiente comando?

SELECT DISTINCT country FROM carmake;

OTRA EDICIÓN: ¿Cuál es el resultado del siguiente comando?

SHOW VARIABLES LIKE 'sql_mode';

Es STRICT_TRANS_TABLESo STRICT_ALL_TABLES? Eso podría conducir a un error, en lugar de la advertencia habitual que MySQL le daría en esta situación.

AÚN OTRA EDICIÓN: Ok, ahora veo que definitivamente tienes valores en la tabla que no están en la nueva ENUM. La nueva ENUMdefinición solo permite 'Sweden'y 'Malaysia'. La mesa tiene 'USA', 'India'y varios otros.

ÚLTIMA EDICIÓN (QUIZÁS): Creo que estás intentando hacer esto

ALTER TABLE carmake CHANGE country country ENUM('Italy', 'Germany', 'England', 'USA', 'France', 'South Korea', 'Australia', 'Spain', 'Czech Republic', 'Sweden', 'Malaysia') DEFAULT NULL;
Asaph
fuente
Hay más de una columna en mi carmakemesa. ¿Podría eso tener algo que ver con eso?
Zaid
1
@ Zaid ten cuidado al decir eso. MySQL es conocido por permitir basura en columnas ENUM. Por ejemplo, convertirá silenciosamente los valores no conformes en cadenas vacías. ¿Estás 100% seguro de que no tienes ningún valor ofensivo? ¿Sin cadenas vacías? ¿Sin espacios en blanco iniciales o finales? Diferencias de casos? ¿Caracteres acentuados?
Asaph
1
@Zaid Creo que tiene valores en su tabla que están ausentes de su definición de ENUM actualizada. Su nueva definición solo permite Suecia y Malasia. Su tabla tiene EE. UU., India, Alemania ... Ninguno de esos valores se permitirá en su nuevo ENUM. Si lo que está tratando de hacer es agregar Suecia y Malasia mientras conserva los miembros originales de ENUM, deberá volver a enumerar todos los valores originales de ENUM más los 2 nuevos en su declaración ALTER.
Asaph
2
@Zaid De nada. Si utiliza una tabla de países con una clave externa en lugar de ENUM, como sugerí anteriormente, simplemente podrá agregar filas para los nuevos países. Por cierto: si mis sugerencias le parecen útiles, marque mi respuesta correcta :)
Asaph
3
-1 Por falta de claridad sobre cuál es la solución real aquí. Hay demasiada conversación y mucho "prueba esto, bueno, prueba esto en su lugar". La respuesta inicial ni siquiera responde a la pregunta real del OP: no es hasta más tarde que te das cuenta de cuál era el problema, y ​​luego entras en ejemplos de código simples que en realidad no significan nada para alguien que está encontrando esta pregunta / respuesta en otro momento. El contexto de sus ediciones es / era temporal, y ya no es obvio.
Jim Rubenstein
73

La discusión que tuve con Asaph puede no estar clara a medida que avanzábamos un poco.

Pensé que podría aclarar el resultado de nuestro discurso para otros que podrían enfrentar situaciones similares en el futuro para beneficiarse de:

ENUMLas columnas de tipo son bestias muy difíciles de manipular. Quería agregar dos países (Malasia y Suecia) al conjunto de países existente en mi ENUM.

Parece que MySQL 5.1 (que es lo que estoy ejecutando) solo puede actualizar el ENUM redefiniendo el conjunto existente además de lo que quiero:

Esto no funcionó:

ALTER TABLE carmake CHANGE country country ENUM('Sweden','Malaysia') DEFAULT NULL;

La razón fue que la declaración de MySQL estaba reemplazando el ENUM existente por otro que contenía las entradas 'Malaysia'y 'Sweden'solo. MySQL arrojó un error porque la carmaketabla ya tenía valores como 'England'y 'USA'que no formaban parte de la nueva ENUMdefinición.

Sorprendentemente, lo siguiente tampoco funcionó:

ALTER TABLE carmake CHANGE country country ENUM('Australia','England','USA'...'Sweden','Malaysia') DEFAULT NULL;

Resulta que incluso el orden de los elementos de los existentes ENUMnecesita ser preservado mientras se le agregan nuevos miembros. Entonces, si mi existente se ENUMparece a algo así ENUM('England','USA'), entonces mi nuevo ENUMdebe definirse como ENUM('England','USA','Sweden','Malaysia')y no ENUM('USA','England','Sweden','Malaysia'). Este problema solo se manifiesta cuando hay registros en la tabla existente que usan 'USA'o 'England'valores.

LÍNEA DE FONDO:

Solo use ENUMs cuando no espere que su conjunto de miembros cambie una vez definido. De lo contrario, las tablas de búsqueda son mucho más fáciles de actualizar y modificar.

Zaid
fuente
Me atrevería con un resultado más sólido ... "solo use ENUMs cuando esté 100% muerto, seguro de que los valores nunca cambiarán". Si una tabla crece, será doloroso si alguna vez tiene que cambiar esos valores.
DougW
66
No estoy seguro de estar de acuerdo con ese resultado final. Confía en mí, no me gustan los ENUM, pero no veo el peligro de AGREGAR el posible ENUM. ENUM es, en esencia, un mapeo de 0 -> Opción 1, 1-> Opción 2, etc. Agregar eso no debería causar un problema.
JoshStrange
2
@JoshStrange No es tanto un peligro, puede ser un gran inconveniente cuando el pedido de su ENUM es importante (por ejemplo, cuando se usa para ordenar).
1in9ui5t
1
Creo que es importante también decir en la línea de fondo que eso es válido solo con versiones heredadas de MySQL porque, por lo que entiendo, con las más nuevas no hay problema.
Niccolò
Esta respuesta ya no es relevante, la siguiente debe marcarse como aceptada.
ofirski
17

En la versión del servidor MYSQL: 5.0.27 probé esto y funcionó bien para mí verificar su versión

ALTER TABLE carmake
     MODIFY `country` ENUM('Japan', 'USA', 'England', 'Australia', 'Germany', 'France', 'Italy', 'Spain', 'Czech Republic', 'China', 'South Korea', 'India', 'Sweden', 'Malaysia');
Abhishek
fuente
1
No estoy seguro de por qué esto no se ha votado más. Es simple y funciona para mí.
ancestral
1

FYI: Una herramienta de simulación útil - phpMyAdmin con Wampserver 3.0.6 - Vista previa de SQL: uso 'Vista previa de SQL' para ver el código SQL que se generaría antes de guardar la columna con el cambio a ENUM. Vista previa de SQL

Arriba puede ver que he ingresado 'Ford', 'Toyota' en el ENUM pero obtengo la sintaxis ENUM (0) que genera un error de sintaxis Error de consulta 1064 #

Luego copio y pego y modifico el SQL y lo ejecuto a través de SQL con un resultado positivo.

SQL cambiado

Esta es una solución rápida que uso con frecuencia y también se puede usar en los valores ENUM existentes que deben modificarse. Pensé que esto podría ser útil.

Addi
fuente
1

Aquí hay otra forma ...

Agrega "otros" a la definición de enumeración de la columna "rtipo" de la tabla "firmas".

set @new_enum = 'others';
set @table_name = 'firmas';
set @column_name = 'rtipo';
select column_type into @tmp from information_schema.columns 
  where table_name = @table_name and column_name=@column_name;
set @tmp = insert(@tmp, instr(@tmp,')'), 0, concat(',\'', @new_enum, '\'') );
set @tmp = concat('alter table ', @table_name, ' modify ', @column_name, ' ', @tmp);
prepare stmt from @tmp;
execute stmt;
deallocate prepare stmt;
Antonio
fuente
-8

Es posible si crees. Jeje. Prueba este código.

public function add_new_enum($new_value)
  {
    $table="product";
    $column="category";
         $row = $this->db->query("SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_NAME = ? AND COLUMN_NAME = ?", array($table, $column))->row_array();

    $old_category = array();
    $new_category="";
    foreach (explode(',', str_replace("'", '', substr($row['COLUMN_TYPE'], 5, (strlen($row['COLUMN_TYPE']) - 6)))) as $val)
    {
        //getting the old category first

        $old_category[$val] = $val;
        $new_category.="'".$old_category[$val]."'".",";
    }

     //after the end of foreach, add the $new_value to $new_category

      $new_category.="'".$new_value."'";

    //Then alter the table column with the new enum

    $this->db->query("ALTER TABLE product CHANGE category category ENUM($new_category)");
  }

Antes de agregar nuevo valor

Después de agregar un nuevo valor

Alj
fuente
11
No veo cómo esto trae algo nuevo a la mesa. La pregunta es puramente desde el punto de vista de MySQL también. Su respuesta incorpora PHP aleatorio que es completamente irrelevante y no intenta explicar nada de eso. Recurso de información inútil
Jonathan