Como adiciono mais membros à minha coluna do tipo ENUM no MySQL?

157

O manual de referência do MySQL não fornece um exemplo claro de como fazer isso.

Eu tenho uma coluna do tipo ENUM de nomes de países aos quais preciso adicionar mais países. Qual é a sintaxe correta do MySQL para conseguir isso?

Aqui está a minha tentativa:

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

O erro que recebo é: ERROR 1265 (01000): Data truncated for column 'country' at row 1.

A countrycoluna é a coluna do tipo ENUM na instrução acima.

MOSTRAR CRIAR SAÍDA DE TABELA :

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)

SELECT DISTINCT country from carmake OUTPUT:

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

Respostas:

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
fonte
7
A maioria dos comandos ALTER TABLE reescreve completamente a tabela inteira. O mysql é inteligente o suficiente para não fazer isso com enum?
John
enum é apenas um número inteiro elegante, com uma representação de string. adicionar itens ao final é bom, pois você apenas adiciona valores antigos significativos. mas alterar a ordem / remover enumerações tornará esses números indefinidos. (por exemplo, 1 => itália, 2 => alemanha), a extensão será (1 => itália, 2 => alemanha, 3 => sweenden).
lintabá 21/03/19
1
@ John depende. Para MariaDB, acrescentando novos valores no final da enumeração pode ser feito inplacedesde 10.3.7: mariadb.com/kb/en/library/...
Felipe Philipp
99

Seu código funciona para mim. Aqui está o meu caso de teste:

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)

Que erro você está vendo?

FWIW, isso também funcionaria:

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

Na verdade, eu recomendaria uma tabela de países em vez de uma coluna enum. Você pode ter centenas de países, o que resultaria em um enum bastante grande e constrangedor.

EDIT: Agora que posso ver sua mensagem de erro:

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

Eu suspeito que você tenha alguns valores na coluna do seu país que não aparecem na sua ENUM. Qual é a saída do seguinte comando?

SELECT DISTINCT country FROM carmake;

OUTRA EDIÇÃO: Qual é a saída do seguinte comando?

SHOW VARIABLES LIKE 'sql_mode';

É STRICT_TRANS_TABLESou STRICT_ALL_TABLES? Isso poderia levar a um erro, ao invés do aviso usual que o MySQL lhe daria nessa situação.

AINDA OUTRA EDIÇÃO: Ok, agora vejo que você definitivamente tem valores na tabela que não estão no novo ENUM. A nova ENUMdefinição permite apenas 'Sweden'e 'Malaysia'. A mesa tem 'USA', 'India'e várias outras.

ÚLTIMA EDIÇÃO (TALVEZ): Acho que você está tentando fazer isso:

ALTER TABLE carmake CHANGE country country ENUM('Italy', 'Germany', 'England', 'USA', 'France', 'South Korea', 'Australia', 'Spain', 'Czech Republic', 'Sweden', 'Malaysia') DEFAULT NULL;
Asaph
fonte
Há mais de uma coluna na minha carmaketabela. Isso poderia ter algo a ver com isso?
Zaid
1
@Zaid tenha cuidado ao dizer isso. O MySQL é notório por permitir lixo nas colunas ENUM. Ele silenciosamente converterá valores não conformes em cadeias vazias, por exemplo. Você tem 100% de certeza de que não possui valores ofensivos? Sem strings vazias? Nenhum espaço em branco à esquerda ou à direita? Diferenças de caso? Caracteres acentuados?
Asaph
1
@Zaid Acho que você tem valores em sua tabela ausentes da sua definição ENUM atualizada. Sua nova definição permite apenas a Suécia e a Malásia. Sua tabela possui EUA, Índia, Alemanha ... Nenhum desses valores será permitido em seu novo ENUM. Se o que você está tentando fazer é adicionar a Suécia e a Malásia, preservando os membros originais do ENUM, você precisará relistar todos os valores originais do ENUM, além dos 2 novos na declaração ALTER.
Asaph
2
@Zaid De nada. Se você usar uma tabela de países com uma chave estrangeira em vez de ENUM, como sugeri no início, você poderá simplesmente adicionar linhas para os novos países. BTW: Se você encontrou minhas sugestões úteis, por favor, marcar a minha resposta correta :)
Asaph
3
-1 Por falta de clareza sobre qual é a solução real aqui. Há muita conversa e muitos "tente isso, oh, tente isso". A resposta inicial nem mesmo responde à pergunta real do OP - é só mais tarde que você percebe qual era o problema e depois entra em exemplos de código simples que não significam nada para alguém que está encontrando essa pergunta / resposta Mais tarde. O contexto de suas edições é / era temporal e não é mais óbvio.
21310 Jim Rubenstein
73

A discussão que tive com Asaph pode não ser clara a seguir, já que andávamos de um lado para o outro.

Eu pensei que poderia esclarecer o resultado do nosso discurso para que outras pessoas que possam enfrentar situações semelhantes no futuro se beneficiem:

ENUMcolunas de tipo são bestas muito difíceis de manipular. Eu queria adicionar dois países (Malásia e Suécia) ao conjunto de países existente no meu ENUM.

Parece que o MySQL 5.1 (que é o que eu estou executando) só pode atualizar o ENUM redefinindo o conjunto existente além do que eu quero:

Isso não funcionou:

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

O motivo foi que a instrução MySQL estava substituindo o ENUM existente por outro contendo as entradas 'Malaysia'e 'Sweden'somente. O MySQL gerou um erro porque a carmaketabela já tinha valores como 'England'e 'USA'que não faziam parte da ENUMdefinição da nova .

Surpreendentemente, o seguinte também não funcionou:

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

Acontece que mesmo a ordem dos elementos do existente ENUMprecisa ser preservada ao adicionar novos membros a ele. Portanto, se o meu existente ENUMparece algo parecido ENUM('England','USA'), então o meu novo ENUMdeve ser definido como ENUM('England','USA','Sweden','Malaysia')e não ENUM('USA','England','Sweden','Malaysia'). Esse problema só se manifesta quando há registros na tabela existente que usam 'USA'ou 'England'valores.

LINHA INFERIOR:

Use ENUMs somente quando você não espera que seu conjunto de membros mude uma vez definido. Caso contrário, as tabelas de pesquisa são muito mais fáceis de atualizar e modificar.

Zaid
fonte
Eu arriscaria uma linha de fundo mais forte ... "só use ENUMs quando você estiver 100% morto, certo de que os valores nunca mudarão". Se uma tabela aumentar, será uma dor se você precisar alterar esses valores.
DougW
6
Não tenho certeza se concordo com esse resultado final. Confie em mim, eu não gosto de ENUM, mas não vejo o perigo de adicionar ao possível ENUM. ENUM é, no seu núcleo, um mapeamento de 0 -> Opção 1, 1-> Opção 2, etc. O acréscimo a isso não deve causar problemas.
21415 JoshStrange #
2
@ JoshStrange Não é tanto um perigo, pode ser um grande inconveniente quando a ordem do seu ENUM é importante (por exemplo, quando usada para fazer pedidos).
1in9ui5t
1
Eu acho que é importante dizer também, no final das contas, que isso é válido apenas nas versões herdadas do MySQL, porque, pelo que entendi, nas versões mais recentes não há problema.
Niccolò
Esta resposta não é mais relevante, a abaixo deve ser marcada como aceita.
ofirski
17

Na versão do servidor MYSQL: 5.0.27, tentei isso e funcionou bem para mim, verifique sua versão

ALTER TABLE carmake
     MODIFY `country` ENUM('Japan', 'USA', 'England', 'Australia', 'Germany', 'France', 'Italy', 'Spain', 'Czech Republic', 'China', 'South Korea', 'India', 'Sweden', 'Malaysia');
Abhishek
fonte
1
Não sei por que isso não foi mais votado. É simples e funciona para mim.
ancestral
1

FYI: Uma ferramenta de simulação útil - phpMyAdmin with Wampserver 3.0.6 - Preview SQL: Eu uso 'Preview SQL' para ver o código SQL que seria gerado antes de salvar a coluna com a alteração ENUM. Visualizar SQL

Acima, você vê que inseri 'Ford', 'Toyota' no ENUM, mas estou recebendo a sintaxe ENUM (0), que está gerando erro de sintaxe Erro de consulta 1064 #

Em seguida, copio e colo e altero o SQL e o executo através do SQL com um resultado positivo.

SQL alterado

Esta é uma correção rápida que uso com freqüência e também pode ser usada em valores ENUM existentes que precisam ser alterados. Achei que isso poderia ser útil.

Addi
fonte
1

Aqui está outra maneira ...

Ele adiciona "outros" à definição enum da coluna "rtipo" da tabela "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
fonte
-8

É possível se você acreditar. Ele Ele. tente 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 adicionar novo valor

Depois de adicionar novo valor

Alj
fonte
11
Não vejo como isso traz algo de novo para a mesa. A questão é puramente também do ponto de vista do MySQL. Sua resposta incorpora PHP aleatório que é completamente irrelevante e você não tenta explicar nada disso. Recurso inútil de informações
Jonathan