Jak dodać więcej członków do mojej kolumny typu ENUM w MySQL?

157

Podręcznik referencyjny MySQL nie zawiera jasnego przykładu, jak to zrobić.

Mam kolumnę typu ENUM z nazwami krajów, do której muszę dodać więcej krajów. Jaka jest prawidłowa składnia MySQL, aby to osiągnąć?

Oto moja próba:

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

Otrzymuję błąd: ERROR 1265 (01000): Data truncated for column 'country' at row 1.

countryKolumna jest kolumną ENUM typu w wyżej oświadczeniu.

POKAŻ STWÓRZ WYJŚCIE TABELI :

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)

WYBIERZ WYRÓŻNIONY kraj Z WYJŚCIA SAMOCHODU :

+----------------+
| country        |
+----------------+
| Italy          |
| Germany        |
| England        |
| USA            |
| France         |
| South Korea    |
| NULL           |
| Australia      |
| Spain          |
| Czech Republic |
+----------------+
Zaid
źródło

Odpowiedzi:

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
źródło
7
Większość poleceń ALTER TABLE całkowicie przepisuje całą tabelę. Czy mysql jest na tyle sprytny, aby nie robić tego z enum?
John
enum to po prostu fantazyjna liczba całkowita z reprezentacją w postaci łańcucha. dodawanie elementów na końcu jest w porządku, ponieważ dodajesz po prostu znaczenie starych wartości. ale zmiana kolejności / usunięcie wyliczeń spowoduje, że liczby te będą niezdefiniowane. (np. 1 => włochy, 2 => niemcy), to rozszerzenie będzie (1 => włochy, 2 => niemcy, 3 => sweenden).
lintabá
1
@John zależy. W przypadku MariaDB dodawanie nowych wartości na końcu wyliczenia można wykonać inplaceod 10.3.7: mariadb.com/kb/en/library/…
Felipe Philipp
99

Twój kod działa dla mnie. Oto mój przypadek testowy:

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)

Jaki błąd widzisz?

FWIW to również zadziała:

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

Właściwie poleciłbym tabelę krajów zamiast kolumny wyliczeniowej. Możesz mieć setki krajów, co byłoby dość dużym i niezręcznym wyliczeniem.

EDYCJA: Teraz widzę Twój komunikat o błędzie:

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

Podejrzewam, że masz pewne wartości w kolumnie swojego kraju, które nie pojawiają się w twoim ENUM. Jaki jest wynik następującego polecenia?

SELECT DISTINCT country FROM carmake;

KOLEJNA EDYCJA: Jaki jest wynik następującego polecenia?

SHOW VARIABLES LIKE 'sql_mode';

Czy to jest STRICT_TRANS_TABLESczy STRICT_ALL_TABLES? Może to prowadzić do błędu, a nie zwykłego ostrzeżenia, które MySQL dałoby w tej sytuacji.

JESZCZE KOLEJNA EDYCJA: Ok, teraz widzę, że na pewno masz w tabeli wartości, których nie ma w nowej ENUM. Nowa ENUMdefinicja zezwala tylko na 'Sweden'i 'Malaysia'. Tabela ma 'USA', 'India'i kilka innych.

OSTATNIA EDYCJA (MOŻE): Myślę, że próbujesz to zrobić:

ALTER TABLE carmake CHANGE country country ENUM('Italy', 'Germany', 'England', 'USA', 'France', 'South Korea', 'Australia', 'Spain', 'Czech Republic', 'Sweden', 'Malaysia') DEFAULT NULL;
Asaf
źródło
W mojej carmaketabeli jest więcej niż jedna kolumna . Czy to może mieć z tym coś wspólnego?
Zaid
1
@Zaid, uważaj, mówiąc to. MySQL jest znany z dopuszczania śmieci do kolumn ENUM. Na przykład po cichu przekonwertuje niezgodne wartości na puste ciągi. Czy na 100% nie masz żadnych obraźliwych wartości? Brak pustych łańcuchów? Brak wiodących lub końcowych spacji? Różnice w przypadku? Znaki z akcentami?
Asaph
1
@Zaid Myślę, że masz w tabeli wartości, których nie ma w zaktualizowanej definicji ENUM. Twoja nowa definicja dopuszcza tylko Szwecję i Malezję. Twój stół zawiera Stany Zjednoczone, Indie, Niemcy… Żadna z tych wartości nie będzie dozwolona w nowym ENUM. Jeśli próbujesz dodać Szwecję i Malezję, zachowując pierwotnych członków ENUM, musisz ponownie wystawić wszystkie oryginalne wartości ENUM oraz 2 nowe w oświadczeniu ALTER.
Asaph
2
@Zaid Nie ma za co. Jeśli używasz tabeli krajów z kluczem obcym zamiast ENUM, jak zasugerowałem na początku, będziesz mógł po prostu dodać wiersze dla nowych krajów. BTW: Jeśli uważasz, że moje sugestie okazały się pomocne, zaznacz moją odpowiedź jako poprawną :)
Asaph
3
-1 Z powodu braku jasności co do rzeczywistego rozwiązania. Jest za dużo rozmów i dużo „spróbuj tego, no cóż, spróbuj tego zamiast tego”. Początkowa odpowiedź nie odpowiada nawet faktycznemu pytaniu OP - dopiero później zdajesz sobie sprawę, na czym polegał problem, a następnie przechodzisz do prostych próbek kodu, które tak naprawdę nic nie znaczą dla kogoś, kto znajduje to pytanie / odpowiedź w późniejszym terminie. Kontekst twoich zmian jest / był czasowy i nie jest już oczywisty.
Jim Rubenstein
73

dyskusja miałem z Asafa mogą być niejasne podążać jak poszliśmy tam i z powrotem całkiem sporo.

Pomyślałem, że mógłbym wyjaśnić konsekwencje naszego dyskursu, aby inni, którzy mogą stanąć w podobnej sytuacji w przyszłości, mogli skorzystać z:

ENUMKolumny typu -type są bestiami bardzo trudnymi do manipulowania. Chciałem dodać dwa kraje (Malezję i Szwecję) do istniejącego zestawu krajów w moim ENUM.

Wygląda na to, że MySQL 5.1 (który jest tym, co używam) może zaktualizować ENUM tylko poprzez przedefiniowanie istniejącego zestawu oprócz tego, co chcę:

To nie zadziałało:

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

Powodem było to, że oświadczenie MySQL został zastąpienia istniejącego ENUM z inną zawierającą wpisy 'Malaysia'i 'Sweden'tylko. MySQL zwrócił błąd, ponieważ carmaketabela zawierała już wartości takie jak 'England'i, 'USA'które nie były częścią nowejENUM definicji.

Co zaskakujące, następujące rozwiązania również nie działały:

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

Okazuje się, że nawet kolejność elementów istniejących ENUMtrzeba zachować przy dodawaniu do niego nowych członków. Więc jeśli mój istniejący ENUMwygląda jakoś ENUM('England','USA'), to mój nowy ENUMmusi być zdefiniowany jako, ENUM('England','USA','Sweden','Malaysia')a nie ENUM('USA','England','Sweden','Malaysia'). Ten problem pojawia się tylko wtedy, gdy istnieją rekordy w istniejącej tabeli, które używają 'USA'lub'England' wartości .

LINIA DOLNA:

Używaj ENUMs tylko wtedy, gdy nie spodziewasz się, że Twój zestaw elementów zmieni się po zdefiniowaniu. W przeciwnym razie tabele przeglądowe są znacznie łatwiejsze do zaktualizowania i zmodyfikowania.

Zaid
źródło
Zaryzykowałbym silniejszy wynik finansowy… „używaj ENUM tylko wtedy, gdy jesteś w 100% martwy, pewny, że wartości nigdy się nie zmienią”. Jeśli tabela się rozrośnie, zmiana tych wartości będzie trudna.
DougW,
6
Nie jestem pewien, czy zgadzam się z tym wnioskiem. Zaufaj mi, w ogóle nie lubię ENUM, ale nie widzę niebezpieczeństwa w DODAWANIU do możliwego ENUM. ENUM jest w istocie mapowaniem 0 -> Opcja 1, 1-> Opcja 2 itd. Dodanie do tego nie powinno powodować problemu.
JoshStrange
2
@JoshStrange To nie jest duże zagrożenie, może to być ogromna niedogodność, gdy ważna jest kolejność Twojego ENUM (na przykład podczas składania zamówienia).
1in9ui5t
1
Myślę, że ważne jest również, aby powiedzieć na koniec, że jest to ważne tylko w starszych wersjach MySQL, ponieważ z tego, co rozumiem, z nowszymi nie ma problemu.
Niccolò
Ta odpowiedź nie ma już znaczenia, poniższa powinna zostać oznaczona jako zaakceptowana.
ofirski
16

W wersji serwera MYSQL: 5.0.27 wypróbowałem to i zadziałało dobrze dla mnie, sprawdź swoją wersję

ALTER TABLE carmake
     MODIFY `country` ENUM('Japan', 'USA', 'England', 'Australia', 'Germany', 'France', 'Italy', 'Spain', 'Czech Republic', 'China', 'South Korea', 'India', 'Sweden', 'Malaysia');
Abhishek
źródło
1
Nie jestem pewien, dlaczego nie jest to bardziej poparte. To proste i działa dla mnie.
rodowy
1

FYI: Przydatne narzędzie do symulacji - phpMyAdmin z Wampserver 3.0.6 - Podgląd SQL: Używam „Podgląd SQL”, aby zobaczyć kod SQL, który zostałby wygenerowany przed zapisaniem kolumny ze zmianą na ENUM. Podgląd SQL

Powyżej widać, że wpisałem 'Ford', 'Toyota' do ENUM, ale otrzymuję składnię ENUM (0), która generuje błąd składni Błąd zapytania 1064 #

Następnie kopiuję i wklejam, zmieniam kod SQL i uruchamiam go przez SQL z wynikiem pozytywnym.

SQL się zmienił

Jest to szybka poprawka, której często używam i może być również używana do istniejących wartości ENUM, które należy zmienić. Pomyślałem, że to może być przydatne.

Addi
źródło
1

Oto inny sposób ...

Dodaje „inne” do definicji wyliczenia kolumny „rtipo” tabeli „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
źródło
-8

Jest to możliwe, jeśli wierzysz. Hehe. wypróbuj ten kod.

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

Przed dodaniem nowej wartości

Po dodaniu nowej wartości

Alj
źródło
11
Nie rozumiem, jak to wnosi coś nowego do stołu. Pytanie jest również z punktu widzenia MySQL. Twoja odpowiedź zawiera przypadkowe PHP, które jest całkowicie nieistotne i nie próbujesz niczego wyjaśniać. Bezużyteczne źródło informacji
Jonathan