Comment ajouter plus de membres à ma colonne de type ENUM dans MySQL?

157

Le manuel de référence MySQL ne fournit pas d'exemple clair sur la façon de procéder.

J'ai une colonne de type ENUM de noms de pays auxquels je dois ajouter plus de pays. Quelle est la syntaxe MySQL correcte pour y parvenir?

Voici ma tentative:

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

L'erreur que j'obtiens est: ERROR 1265 (01000): Data truncated for column 'country' at row 1.

La countrycolonne est la colonne de type ENUM dans l'instruction ci-dessus.

AFFICHER LA SORTIE CRÉER LA TABLE :

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)

CHOISISSEZ DISTINCT le pays DE LA SORTIE carmake

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

Réponses:

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
la source
7
La plupart des commandes ALTER TABLE réécrivent complètement la table entière. MySQL est-il assez intelligent pour ne pas faire ça avec enum?
John
enum est juste un entier de fantaisie, avec une représentation sous forme de chaîne. l'ajout d'éléments à la fin est très bien, car vous ajoutez simplement des anciennes valeurs significatives. mais changer l'ordre / supprimer les énumérations rendra ces nombres indéfinis. (par exemple. 1 => italie, 2 => allemagne), puis l'extension sera (1 => italie, 2 => allemagne, 3 => sweenden).
lintabá
1
@John dépend. Pour MariaDB, l'ajout de nouvelles valeurs à la fin de l'énumération peut être fait inplacedepuis le 10.3.7: mariadb.com/kb/en/library/…
Felipe Philipp
99

Votre code fonctionne pour moi. Voici mon cas de test:

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)

Quelle erreur voyez-vous?

FWIW cela fonctionnerait également:

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

Je recommanderais en fait une table de pays plutôt qu'une colonne enum. Il se peut que vous ayez des centaines de pays, ce qui constituerait une énumération assez importante et maladroite.

EDIT: Maintenant que je peux voir votre message d'erreur:

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

Je soupçonne que vous avez des valeurs dans la colonne de votre pays qui n'apparaissent pas dans votre ENUM. Quelle est la sortie de la commande suivante?

SELECT DISTINCT country FROM carmake;

UNE AUTRE MODIFICATION: Quelle est la sortie de la commande suivante?

SHOW VARIABLES LIKE 'sql_mode';

Est-ce STRICT_TRANS_TABLESou STRICT_ALL_TABLES? Cela pourrait entraîner une erreur, plutôt que l'avertissement habituel que MySQL vous donnerait dans cette situation.

ENCORE UNE AUTRE MODIFICATION: Ok, je vois maintenant que vous avez certainement des valeurs dans le tableau qui ne sont pas dans le nouveau ENUM. La nouvelle ENUMdéfinition autorise uniquement 'Sweden'et 'Malaysia'. La table a 'USA', 'India'et plusieurs autres.

DERNIÈRE MODIFICATION (PEUT-ÊTRE): Je pense que vous essayez de faire ceci:

ALTER TABLE carmake CHANGE country country ENUM('Italy', 'Germany', 'England', 'USA', 'France', 'South Korea', 'Australia', 'Spain', 'Czech Republic', 'Sweden', 'Malaysia') DEFAULT NULL;
Asaph
la source
Il y a plus d'une colonne dans mon carmaketableau. Cela pourrait-il avoir quelque chose à voir avec cela?
Zaid
1
@Zaid faites attention à ne pas dire ça. MySQL est connu pour autoriser les déchets dans les colonnes ENUM. Il convertira silencieusement les valeurs non conformes en chaînes vides, par exemple. Êtes-vous sûr à 100% de ne pas avoir de valeurs offensantes? Pas de chaînes vides? Aucun espace blanc de début ou de fin? Différences de cas? Caractères accentués?
Asaph
1
@Zaid Je pense que vous avez des valeurs dans votre table qui sont absentes de votre définition ENUM mise à jour. Votre nouvelle définition n'autorise que la Suède et la Malaisie. Votre table contient USA, Inde, Allemagne ... Aucune de ces valeurs ne sera autorisée dans votre nouvel ENUM. Si ce que vous essayez de faire est d' ajouter la Suède et la Malaisie tout en préservant les membres originaux de l'ENUM, vous devrez remettre en vente toutes les valeurs ENUM d'origine plus les 2 nouvelles dans votre instruction ALTER.
Asaph
2
@Zaid De rien. Si vous utilisez une table de pays avec une clé étrangère au lieu de l'ENUM comme je l'ai suggéré au début, vous pourrez simplement ajouter des lignes pour les nouveaux pays. BTW: Si vous avez trouvé mes suggestions utiles, veuillez marquer ma réponse comme étant correcte :)
Asaph
3
-1 Par manque de clarté sur la solution actuelle. Il y a trop de conversations et beaucoup de "essayez ceci, eh bien essayez ceci à la place." La réponse initiale ne répond même pas à la question réelle du PO - ce n'est que plus tard que vous réalisez quel était le problème, puis vous entrez dans des échantillons de code simples qui ne signifient rien pour quelqu'un qui trouve cette question / réponse à un moment ultérieur. Le contexte de vos modifications est / était temporel et n'est plus évident.
Jim Rubenstein le
73

La discussion que j'ai eue avec Asaph n'est peut-être pas claire à suivre, car nous nous sommes allés un peu en arrière.

J'ai pensé que je pourrais clarifier le résultat de notre discours pour que d'autres qui pourraient faire face à des situations similaires à l'avenir bénéficient de:

ENUMLes colonnes de type -type sont des bêtes très difficiles à manipuler. Je voulais ajouter deux pays (Malaisie et Suède) à l'ensemble de pays existant dans mon ENUM.

Il semble que MySQL 5.1 (qui est ce que j'utilise) ne peut mettre à jour l'ENUM qu'en redéfinissant l'ensemble existant en plus de ce que je veux:

Cela n'a pas fonctionné:

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

La raison en était que l'instruction MySQL remplaçait l'ENUM existant par un autre contenant les entrées 'Malaysia'et 'Sweden'uniquement. MySQL a renvoyé une erreur car la carmaketable avait déjà des valeurs comme 'England'et 'USA'qui ne faisaient pas partie de la nouvelle ENUMdéfinition.

Étonnamment, ce qui suit n'a pas fonctionné non plus:

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

Il s'avère que même l'ordre des éléments de l'existant ENUMdoit être préservé tout en y ajoutant de nouveaux membres. Donc, si mon existant ENUMressemble à quelque chose ENUM('England','USA'), alors mon nouveau ENUMdoit être défini comme ENUM('England','USA','Sweden','Malaysia')et non ENUM('USA','England','Sweden','Malaysia'). Ce problème ne devient manifeste que lorsqu'il existe des enregistrements dans la table existante qui utilisent 'USA'ou des 'England'valeurs.

LIGNE INFERIEURE:

N'utilisez ENUMs que lorsque vous ne vous attendez pas à ce que votre ensemble de membres change une fois défini. Sinon, les tables de consultation sont beaucoup plus faciles à mettre à jour et à modifier.

Zaid
la source
Je risquerais un résultat plus fort ... "N'utilisez les ENUM que lorsque vous êtes à 100% certain que les valeurs ne changeront jamais". Si une table devient grande, ce sera pénible si vous devez un jour changer ces valeurs.
DougW
6
Je ne suis pas sûr d'être d'accord avec ce résultat. Croyez-moi, je n'aime pas du tout ENUM mais je ne vois pas le danger de AJOUTER au possible ENUM. ENUM est, au fond, un mappage de 0 -> Option 1, 1-> Option 2, etc. Ajouter à cela ne devrait pas poser de problème.
JoshStrange
2
@JoshStrange Ce n'est pas tant un danger, cela peut être un gros inconvénient lorsque l'ordre de votre ENUM est important (par exemple, lorsqu'il est utilisé pour commander).
1in9ui5t
1
Je pense qu'il est également important de dire en fin de compte que cela n'est valable qu'avec les anciennes versions de MySQL, car pour ce que je comprends, avec les plus récentes, il n'y a pas de problème.
Niccolò
Cette réponse n'est plus pertinente, celle ci-dessous doit être marquée comme acceptée.
ofirski
17

Dans la version du serveur MYSQL: 5.0.27, j'ai essayé cela et cela a bien fonctionné pour moi, vérifiez votre version

ALTER TABLE carmake
     MODIFY `country` ENUM('Japan', 'USA', 'England', 'Australia', 'Germany', 'France', 'Italy', 'Spain', 'Czech Republic', 'China', 'South Korea', 'India', 'Sweden', 'Malaysia');
Abhishek
la source
1
Je ne sais pas pourquoi ce n'est pas plus voté. C'est simple et ça marche pour moi.
ancestral
1

FYI: Un outil de simulation utile - phpMyAdmin avec Wampserver 3.0.6 - Preview SQL: J'utilise 'Preview SQL' pour voir le code SQL qui serait généré avant d'enregistrer la colonne avec le changement en ENUM. Aperçu SQL

Ci-dessus, vous voyez que j'ai entré 'Ford', 'Toyota' dans ENUM mais j'obtiens la syntaxe ENUM (0) qui génère une erreur de syntaxe Erreur de requête 1064 #

Ensuite, je copie et colle et modifie le SQL et l'exécute via SQL avec un résultat positif.

SQL changé

C'est un correctif rapide que j'utilise souvent et qui peut également être utilisé sur les valeurs ENUM existantes qui doivent être modifiées. J'ai pensé que cela pourrait être utile.

Addi
la source
1

Voici une autre façon ...

Il ajoute "autres" à la définition enum de la colonne "rtipo" de la table "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
la source
-8

C'est possible si vous croyez. Hehe. essayez ce code.

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)");
  }

Avant d'ajouter une nouvelle valeur

Après avoir ajouté une nouvelle valeur

Alj
la source
11
Je ne vois pas en quoi cela apporte quelque chose de nouveau à la table. La question est également purement du point de vue de MySQL. Votre réponse incorpore du PHP aléatoire qui est totalement hors de propos et vous ne tentez pas d'expliquer quoi que ce soit. Ressource d'information inutile
Jonathan