Wie füge ich meiner Spalte vom Typ ENUM in MySQL weitere Mitglieder hinzu?

157

Das MySQL-Referenzhandbuch enthält kein eindeutiges Beispiel dafür.

Ich habe eine ENUM-Spalte mit Ländernamen, zu denen ich weitere Länder hinzufügen muss. Was ist die richtige MySQL-Syntax, um dies zu erreichen?

Hier ist mein Versuch:

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

Der Fehler, den ich bekomme, ist: ERROR 1265 (01000): Data truncated for column 'country' at row 1.

Die countrySpalte ist die Spalte vom Typ ENUM in der obigen Anweisung.

SHOW CREATE TABLE OUTPUT:

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)

WÄHLEN SIE EIN UNTERSCHIEDLICHES LAND AUS DER Carmake-AUSGABE:

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

Antworten:

134
ALTER TABLE
    `table_name`
MODIFY COLUMN
    `column_name2` enum(
        'existing_value1',
        'existing_value2',
        'new_value1',
        'new_value2'
    )
NOT NULL AFTER `column_name1`;
Pradip Chongbang
quelle
7
Die meisten ALTER TABLE-Befehle schreiben die gesamte Tabelle vollständig neu. Ist MySQL klug genug, um das nicht mit Enum zu tun?
John
enum ist nur eine ausgefallene Ganzzahl mit einer Zeichenfolgendarstellung. Das Hinzufügen von Elementen am Ende ist in Ordnung, da Sie nur alte Bedeutungswerte hinzufügen. Durch Ändern der Reihenfolge / Entfernen von Aufzählungen werden diese Zahlen jedoch undefiniert. (zB 1 => Italien, 2 => Deutschland), dann wird erweitert (1 => Italien, 2 => Deutschland, 3 => Sweenden).
Lintabá
1
@ John hängt davon ab. Für MariaDB kann das Hinzufügen neuer Werte am Ende der Aufzählung inplaceseit 10.3.7 erfolgen: mariadb.com/kb/en/library/…
Felipe Philipp
99

Ihr Code funktioniert für mich. Hier ist mein Testfall:

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)

Welchen Fehler sehen Sie?

FWIW das würde auch funktionieren:

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

Ich würde eigentlich eher eine Ländertabelle als eine Aufzählungsspalte empfehlen. Möglicherweise haben Sie Hunderte von Ländern, die zu einer ziemlich großen und umständlichen Aufzählung führen würden.

EDIT: Jetzt, wo ich Ihre Fehlermeldung sehen kann:

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

Ich vermute, Sie haben einige Werte in Ihrer Länderspalte, die nicht in Ihrer angezeigt werden ENUM. Was ist die Ausgabe des folgenden Befehls?

SELECT DISTINCT country FROM carmake;

EINE ANDERE BEARBEITUNG: Was ist die Ausgabe des folgenden Befehls?

SHOW VARIABLES LIKE 'sql_mode';

Ist es STRICT_TRANS_TABLESoder STRICT_ALL_TABLES? Dies könnte zu einem Fehler führen und nicht zu der üblichen Warnung, die MySQL in dieser Situation geben würde.

NOCH EINE ANDERE BEARBEITUNG: Ok, ich sehe jetzt, dass Sie definitiv Werte in der Tabelle haben, die nicht in der neuen sind ENUM. Die neue ENUMDefinition erlaubt nur 'Sweden'und 'Malaysia'. Die Tabelle hat 'USA', 'India'und einige andere.

LAST EDIT (MÖGLICHERWEISE): Ich denke, Sie versuchen dies zu tun:

ALTER TABLE carmake CHANGE country country ENUM('Italy', 'Germany', 'England', 'USA', 'France', 'South Korea', 'Australia', 'Spain', 'Czech Republic', 'Sweden', 'Malaysia') DEFAULT NULL;
Asaph
quelle
Es gibt mehr als eine Spalte in meiner carmakeTabelle. Könnte das etwas damit zu tun haben?
Zaid
1
@Zaid sei vorsichtig damit. MySQL ist dafür berüchtigt, Müll in ENUM-Spalten zuzulassen. Beispielsweise werden fehlerhafte Werte stillschweigend in leere Zeichenfolgen konvertiert. Sind Sie zu 100% sicher, dass Sie keine beleidigenden Werte haben? Keine leeren Saiten? Kein führendes oder nachfolgendes Leerzeichen? Fallunterschiede? Zeichen mit Akzent?
Asaph
1
@Zaid Ich denke, Sie haben Werte in Ihrer Tabelle, die in Ihrer aktualisierten ENUM-Definition nicht enthalten sind. Ihre neue Definition erlaubt nur Schweden und Malaysia. Ihre Tabelle enthält USA, Indien, Deutschland ... Keiner dieser Werte ist in Ihrer neuen ENUM zulässig. Wenn Sie versuchen, Schweden und Malaysia hinzuzufügen, während die ursprünglichen Mitglieder der ENUM erhalten bleiben, müssen Sie alle ursprünglichen ENUM-Werte sowie die beiden neuen Werte in Ihrer ALTER-Anweisung erneut auflisten .
Asaph
2
@Zaid Gern geschehen. Wenn Sie eine Ländertabelle mit einem Fremdschlüssel anstelle der ENUM verwenden, wie ich bereits vorgeschlagen habe, können Sie einfach Zeilen für die neuen Länder hinzufügen. Übrigens: Wenn Sie meine Vorschläge hilfreich fanden, markieren Sie bitte meine Antwort als richtig :)
Asaph
3
-1 Aus Mangel an Klarheit darüber, was die eigentliche Lösung hier ist. Es gibt zu viele Gespräche und viele "versuchen Sie das, na ja, versuchen Sie es stattdessen." Die erste Antwort beantwortet nicht einmal die eigentliche Frage des OP - erst später erkennen Sie, was das Problem war, und gehen dann auf einfache Codebeispiele ein, die für jemanden, der diese Frage / Antwort findet, eigentlich nichts bedeuten zu einem späteren Zeitpunkt. Der Kontext Ihrer Änderungen ist / war zeitlich begrenzt und nicht mehr offensichtlich.
Jim Rubenstein
73

Die Diskussion, die ich mit Asaph geführt habe, ist möglicherweise unklar, da wir ziemlich viel hin und her gingen.

Ich dachte, ich könnte das Ergebnis unseres Diskurses für andere klarstellen, die in Zukunft möglicherweise mit ähnlichen Situationen konfrontiert sind, um davon zu profitieren:

ENUMSpalten vom Typ sind sehr schwer zu manipulierende Bestien. Ich wollte zwei Länder (Malaysia und Schweden) zu den bestehenden Ländern in meiner ENUM hinzufügen.

Es scheint, dass MySQL 5.1 (das ist, was ich ausführe) die ENUM nur aktualisieren kann, indem das vorhandene Set zusätzlich zu dem, was ich will, neu definiert wird:

Das hat nicht funktioniert:

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

Der Grund dafür war , dass die MySQL - Anweisung wurde ersetzt die bestehende ENUM mit einem anderen die Einträge enthält , 'Malaysia'und 'Sweden'nur. MySQL hat einen Fehler ausgegeben, da die carmakeTabelle bereits Werte wie 'England'und 'USA'enthielt, die nicht Teil der ENUMDefinition des neuen waren .

Überraschenderweise funktionierte auch Folgendes nicht:

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

Es stellt sich heraus, dass auch die Reihenfolge der Elemente des vorhandenen ENUMbeibehalten werden muss, während neue Mitglieder hinzugefügt werden. Wenn mein bestehendes ENUMungefähr so ​​aussieht ENUM('England','USA'), muss mein neues ENUMdefiniert werden als ENUM('England','USA','Sweden','Malaysia')und nicht ENUM('USA','England','Sweden','Malaysia'). Dieses Problem wird nur manifestieren , wenn es Datensätze in der vorhandenen Tabelle , dass die Verwendung 'USA'oder 'England'Werte.

ENDEFFEKT:

Verwenden Sie ENUMs nur, wenn Sie nicht erwarten, dass sich Ihre Mitglieder nach der Definition ändern. Andernfalls lassen sich Nachschlagetabellen viel einfacher aktualisieren und ändern.

Zaid
quelle
Ich würde ein stärkeres Endergebnis wagen ... "Verwenden Sie ENUMs nur, wenn Sie zu 100% tot sind und sicher sind, dass sich die Werte niemals ändern werden". Wenn eine Tabelle groß wird, ist es schmerzhaft, wenn Sie diese Werte jemals ändern müssen.
DougW
6
Ich bin mir nicht sicher, ob ich diesem Fazit zustimme. Vertrauen Sie mir, ich mag ENUMs überhaupt nicht, aber ich sehe die Gefahr nicht darin, dem möglichen ENUM HINZUFÜGEN. ENUM ist im Kern eine Zuordnung von 0 -> Option 1, 1-> Option 2 usw. Das Hinzufügen sollte kein Problem verursachen.
JoshStrange
2
@JoshStrange Es ist nicht so sehr eine Gefahr, es kann eine große Unannehmlichkeit sein, wenn die Reihenfolge Ihrer ENUM wichtig ist (zum Beispiel, wenn sie für die Bestellung verwendet wird).
1in9ui5t
1
Ich denke, es ist auch wichtig, unter dem Strich zu sagen, dass dies nur für ältere Versionen von MySQL gilt, da es meines Wissens bei neueren Versionen kein Problem gibt.
Niccolò
Diese Antwort ist nicht mehr relevant, die folgende sollte als akzeptiert markiert werden.
ofirski
16

In MYSQL Server Version: 5.0.27 habe ich dies versucht und es hat gut funktioniert, wenn ich Ihre Version einchecke

ALTER TABLE carmake
     MODIFY `country` ENUM('Japan', 'USA', 'England', 'Australia', 'Germany', 'France', 'Italy', 'Spain', 'Czech Republic', 'China', 'South Korea', 'India', 'Sweden', 'Malaysia');
Abhishek
quelle
1
Ich bin mir nicht sicher, warum dies nicht mehr positiv bewertet wird. Es ist einfach und funktioniert bei mir.
Ahnen
1

Zu Ihrer Information: Ein nützliches Simulationswerkzeug - phpMyAdmin mit Wampserver 3.0.6 - SQL-Vorschau: Ich verwende 'SQL-Vorschau', um den SQL-Code anzuzeigen, der generiert wird, bevor Sie die Spalte mit der Änderung in ENUM speichern. Vorschau von SQL

Oben sehen Sie, dass ich 'Ford', 'Toyota' in die ENUM eingegeben habe, aber die Syntax ENUM (0) erhalte, die einen Syntaxfehler generiert. Abfragefehler 1064 #

Ich kopiere und füge dann das SQL ein und ändere es und führe es mit einem positiven Ergebnis durch SQL.

SQL geändert

Dies ist ein Quickfix, den ich häufig verwende und der auch für vorhandene ENUM-Werte verwendet werden kann, die geändert werden müssen. Dachte, das könnte nützlich sein.

Addi
quelle
1

Hier ist ein anderer Weg ...

Es fügt "andere" zur Aufzählungsdefinition der Spalte "rtipo" der Tabelle "firmas" hinzu.

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
quelle
-8

Es ist möglich, wenn Sie glauben. Hehe. Versuchen Sie diesen 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)");
  }

Vor dem Hinzufügen eines neuen Werts

Nach dem Hinzufügen eines neuen Wertes

Alj
quelle
11
Ich sehe nicht, wie das etwas Neues auf den Tisch bringt. Die Frage ist auch rein aus MySQL-Sicht. Ihre Antwort enthält zufälliges PHP, das völlig irrelevant ist, und Sie machen keinen Versuch, irgendetwas davon zu erklären. Nutzlose Informationsquelle
Jonathan