Come faccio ad aggiungere più membri alla mia colonna di tipo ENUM in MySQL?


157

Il manuale di riferimento di MySQL non fornisce un chiaro esempio su come eseguire questa operazione.

Ho una colonna di nomi ENUM di tipo paese a cui devo aggiungere altri paesi. Qual è la sintassi MySQL corretta per raggiungere questo obiettivo?

Ecco il mio tentativo:

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

L'errore che ottengo è: ERROR 1265 (01000): Data truncated for column 'country' at row 1.

La countrycolonna è la colonna di tipo ENUM nell'istruzione precedente.

VISUALIZZA CREA USCITA TABELLA :

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)

SELEZIONA DISTINCT paese DALL'USCITA del carmake :

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

Risposte:


135
ALTER TABLE
    `table_name`
MODIFY COLUMN
    `column_name2` enum(
        'existing_value1',
        'existing_value2',
        'new_value1',
        'new_value2'
    )
NOT NULL AFTER `column_name1`;

7
La maggior parte dei comandi ALTER TABLE riscriverà completamente l'intera tabella. Mysql è abbastanza intelligente da non farlo con enum?
Giovanni,

enum è solo un intero di fantasia, con una rappresentazione in formato stringa. l'aggiunta di elementi alla fine va bene, dal momento che aggiungi solo significati vecchi valori. ma cambiare l'ordine / rimuovere gli enumerazioni renderà indefiniti quei numeri. (es. 1 => italia, 2 => germania), quindi l'estensione sarà (1 => italia, 2 => germania, 3 => sweenden).
1919

1
@John dipende. Per MariaDB, l'aggiunta di nuovi valori alla fine dell'enum può essere effettuata inplacedal 10.3.7: mariadb.com/kb/en/library/…
Felipe Philipp,

99

Il tuo codice funziona per me. Ecco il mio caso di 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)

Che errore stai vedendo?

FWIW questo funzionerebbe anche:

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

Vorrei davvero raccomandare una tabella di paese piuttosto che la colonna enum. Potresti avere centinaia di paesi che costituirebbero un enum piuttosto grande e imbarazzante.

EDIT: Ora che posso vedere il tuo messaggio di errore:

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

Ho il sospetto che tu abbia alcuni valori nella colonna del tuo paese che non compaiono nella tua ENUM. Qual è l'output del seguente comando?

SELECT DISTINCT country FROM carmake;

UN ALTRO EDIT: Qual è l'output del seguente comando?

SHOW VARIABLES LIKE 'sql_mode';

È STRICT_TRANS_TABLESo STRICT_ALL_TABLES? Ciò potrebbe causare un errore, piuttosto che il solito avvertimento che MySQL ti darebbe in questa situazione.

ANCORA UN ALTRO EDIT: Ok, ora vedo che hai sicuramente dei valori nella tabella che non sono nella nuova ENUM. La nuova ENUMdefinizione consente solo 'Sweden'e 'Malaysia'. Il tavolo ha 'USA', 'India'e molti altri.

ULTIMA MODIFICA (FORSE): Penso che tu stia provando a fare questo:

ALTER TABLE carmake CHANGE country country ENUM('Italy', 'Germany', 'England', 'USA', 'France', 'South Korea', 'Australia', 'Spain', 'Czech Republic', 'Sweden', 'Malaysia') DEFAULT NULL;

C'è più di una colonna nella mia carmaketabella. Potrebbe avere qualcosa a che fare con esso?
Zaid

1
@Zaid stai attento a dirlo. MySQL è noto per consentire la spazzatura nelle colonne ENUM. Ad esempio, convertirà silenziosamente i valori non conformi in stringhe vuote. Sei sicuro al 100% di non avere valori offensivi? Nessuna stringa vuota? Nessuno spazio bianco iniziale o finale? Differenze di caso? Personaggi accentati?
Asaph,

1
@Zaid Penso che tu abbia dei valori nella tua tabella che sono assenti dalla tua definizione ENUM aggiornata. La tua nuova definizione consente solo Svezia e Malesia. La tua tabella ha USA, India, Germania ... Nessuno di questi valori sarà permesso nel tuo nuovo ENUM. Se quello che stai tentando di fare è aggiungere Svezia e Malesia preservando i membri originali di ENUM, dovrai rielaborare tutti i valori ENUM originali più i 2 nuovi nella tua dichiarazione ALTER.
Asaph,

2
@Zaid Prego. Se usi una tabella di paesi con una chiave esterna anziché ENUM, come ho suggerito all'inizio, sarai in grado di aggiungere semplicemente righe per i nuovi paesi. A proposito: se hai trovato utili i miei suggerimenti, ti preghiamo di contrassegnare la mia risposta corretta :)
Asaph

3
-1 Per mancanza di chiarezza su quale sia la soluzione effettiva qui. C'è troppa conversazione e un sacco di "prova questo, oh beh prova questo invece". La risposta iniziale non risponde nemmeno alla domanda effettiva del PO: non è più tardi che ti rendi conto del problema, e poi vai in semplici esempi di codice che in realtà non significano nulla per qualcuno che sta trovando questa domanda / risposta più tardi. Il contesto delle tue modifiche è / era temporale e non è più ovvio.
Jim Rubenstein,

73

La discussione che ho avuto con Asaph potrebbe non essere chiara da seguire mentre andavamo avanti e indietro un po '.

Ho pensato che avrei potuto chiarire l'esito del nostro discorso per gli altri che potrebbero affrontare situazioni simili in futuro per beneficiare di:

ENUMle colonne di tipo sono animali molto difficili da manipolare. Volevo aggiungere due paesi (Malesia e Svezia) all'insieme esistente di paesi nel mio ENUM.

Sembra che MySQL 5.1 (che è quello che sto eseguendo) possa aggiornare ENUM solo ridefinendo il set esistente oltre a quello che voglio:

Questo non ha funzionato:

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

Il motivo era che la dichiarazione MySQL stava sostituendo l'ENUM esistente con un'altra contenente le voci 'Malaysia'e 'Sweden'solo. MySQL ha generato un errore perché la carmaketabella aveva già valori simili 'England'e 'USA'che non facevano parte della nuova ENUMdefinizione.

Sorprendentemente, neanche il seguente ha funzionato:

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

Si scopre che anche l'ordine degli elementi dell'esistente ENUMdeve essere preservato mentre si aggiungono nuovi membri. Quindi, se il mio esistente ENUMsembra qualcosa del genere ENUM('England','USA'), allora il mio nuovo ENUMdeve essere definito come ENUM('England','USA','Sweden','Malaysia')e non ENUM('USA','England','Sweden','Malaysia'). Questo problema si manifesta solo quando nella tabella esistente sono presenti record che utilizzano 'USA'o 'England'valori.

LINEA DI FONDO:

Usa ENUMs solo quando non prevedi che il tuo gruppo di membri cambi una volta definito. Altrimenti, le tabelle di ricerca sono molto più facili da aggiornare e modificare.


Vorrei avventurarmi in una linea di fondo più forte ... "Usa ENUM solo quando sei morto al 100%, certo che i valori non cambieranno mai". Se una tabella diventa grande, sarà un dolore se dovessi mai cambiare questi valori.
DougW

6
Non sono sicuro di essere d'accordo con quella linea di fondo. Fidati di me, non mi piacciono affatto gli ENUM ma non vedo il pericolo di AGGIUNGERE al possibile ENUM. ENUM è, al suo centro, una mappatura di 0 -> Opzione 1, 1-> Opzione 2, ecc. L'aggiunta a questo non dovrebbe causare problemi.
JoshStrange,

2
@JoshStrange Non è tanto un pericolo, può essere un grosso inconveniente quando l'ordine del tuo ENUM è importante (ad esempio, se utilizzato per l'ordinazione).
1in9ui5t,

1
Penso che sia importante anche dire in fondo che ciò è valido solo con le versioni legacy di MySQL perché per quello che capisco, con quelli più recenti non c'è nessun problema.
Niccolò,

Questa risposta non è più pertinente, quella sotto dovrebbe essere contrassegnata come accettata.
Ofirski,

17

Nella versione server MYSQL: 5.0.27 ho provato questo e ha funzionato bene per me controllare nella tua versione

ALTER TABLE carmake
     MODIFY `country` ENUM('Japan', 'USA', 'England', 'Australia', 'Germany', 'France', 'Italy', 'Spain', 'Czech Republic', 'China', 'South Korea', 'India', 'Sweden', 'Malaysia');

1
Non sono sicuro del perché questo non sia più votato. È semplice e funziona per me.
ancestrale

1

FYI: un utile strumento di simulazione - phpMyAdmin con Wampserver 3.0.6 - Anteprima SQL: utilizzo "Anteprima SQL" per vedere il codice SQL che verrebbe generato prima di salvare la colonna con la modifica in ENUM. Anteprima SQL

Sopra vedi che ho inserito 'Ford', 'Toyota' nell'ENUM ma sto ottenendo la sintassi ENUM (0) che sta generando errore di sintassi Errore di query 1064 #

Quindi copio e incollo e modifico l'SQL e lo eseguo tramite SQL con un risultato positivo.

SQL modificato

Questa è una soluzione rapida che uso spesso e può essere utilizzata anche su valori ENUM esistenti che devono essere modificati. Ho pensato che potesse essere utile.


1

Ecco un altro modo ...

Aggiunge "altri" alla definizione enum della colonna "rtipo" della tabella "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;

-8

È possibile se ci credi. Hehe. prova questo codice.

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

Prima di aggiungere un nuovo valore

Dopo aver aggiunto un nuovo valore


11
Non vedo come questo porti qualcosa di nuovo sul tavolo. La domanda è puramente anche dal punto di vista di MySQL. La tua risposta incorpora PHP casuale che è completamente irrilevante e non fai alcun tentativo di spiegarlo. Inutile risorsa di informazioni
Jonathan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.