Как мне добавить больше членов к моему столбцу ENUM-типа в MySQL?

157

Справочное руководство по MySQL не дает четкого примера того, как это сделать.

У меня есть столбец с названиями стран в формате ENUM, к которому нужно добавить больше стран. Какой правильный синтаксис MySQL для этого?

Вот моя попытка:

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

Я получаю ошибку: ERROR 1265 (01000): Data truncated for column 'country' at row 1.

countryСтолбец является ENUM-типа в вышеприведенном заявлении.

ПОКАЗАТЬ СОЗДАТЬ ТАБЛИЦУ ВЫХОД:

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)

ВЫБЕРИТЕ РАЗЛИЧНУЮ страну ОТ АВТОМОБИЛЬНОГО ВЫХОДА:

+----------------+
| country        |
+----------------+
| Italy          |
| Germany        |
| England        |
| USA            |
| France         |
| South Korea    |
| NULL           |
| Australia      |
| Spain          |
| Czech Republic |
+----------------+
Зайд
источник

Ответы:

135
ALTER TABLE
    `table_name`
MODIFY COLUMN
    `column_name2` enum(
        'existing_value1',
        'existing_value2',
        'new_value1',
        'new_value2'
    )
NOT NULL AFTER `column_name1`;
Прадип Чонгбанг
источник
7
Большинство команд ALTER TABLE полностью переписывают всю таблицу. Является ли mysql достаточно умным, чтобы не делать этого с enum?
Джон
enum - это просто необычное целое число со строковым представлением. добавление элементов в конец - это нормально, так как вы просто добавляете значения старых значений. но изменение порядка / удаление перечислений сделает эти числа неопределенными. (например, 1 => Италия, 2 => Германия), тогда расширение будет (1 => Италия, 2 => Германия, 3 => Швейцария).
lintabá
1
@ Джон зависит. Для MariaDB добавление новых значений в конце перечисления может быть сделано inplaceначиная с 10.3.7: mariadb.com/kb/en/library/…
Фелипе Филипп
99

Ваш код работает для меня. Вот мой тестовый пример:

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)

Какую ошибку вы видите?

FWIW это также будет работать:

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

Я бы порекомендовал таблицу стран, а не столбец enum. У вас могут быть сотни стран, которые могут составить довольно большой и неуклюжий список.

РЕДАКТИРОВАТЬ: Теперь, когда я вижу ваше сообщение об ошибке:

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

Я подозреваю, что у вас есть некоторые значения в столбце вашей страны, которые не отображаются в вашем ENUM. Каков вывод следующей команды?

SELECT DISTINCT country FROM carmake;

ДРУГОЕ РЕДАКТИРОВАНИЕ: Каковы выходные данные следующей команды?

SHOW VARIABLES LIKE 'sql_mode';

Это STRICT_TRANS_TABLESили STRICT_ALL_TABLES? Это может привести к ошибке, а не к обычному предупреждению, которое MySQL даст вам в этой ситуации.

ЕЩЕ ДРУГОЕ РЕДАКТИРОВАНИЕ: Хорошо, теперь я вижу, что у вас определенно есть значения в таблице, которых нет в новом ENUM. Новое ENUMопределение позволяет только 'Sweden'и 'Malaysia'. В таблице есть 'USA', 'India'и некоторые другие.

ПОСЛЕДНИЕ РЕДАКТИРОВАТЬ (МОЖЕТ): Я думаю, что вы пытаетесь сделать это:

ALTER TABLE carmake CHANGE country country ENUM('Italy', 'Germany', 'England', 'USA', 'France', 'South Korea', 'Australia', 'Spain', 'Czech Republic', 'Sweden', 'Malaysia') DEFAULT NULL;
Асаф
источник
В моей carmakeтаблице более одного столбца . Может ли это иметь какое-либо отношение к этому?
Заид
1
@ Говори об этом осторожно. MySQL печально известен тем, что допускает сбор мусора в столбцы ENUM. Например, он будет молча преобразовывать несоответствующие значения в пустые строки. Вы на 100% уверены, что у вас нет оскорбительных значений? Нет пустых строк? Нет лидирующих или конечных пробелов? Случайные различия? Бывают персонажи?
Асаф
1
@Zaid Я думаю, у вас есть значения в вашей таблице, которые отсутствуют в вашем обновленном определении ENUM. Ваше новое определение позволяет только Швеция и Малайзия. В вашей таблице есть США, Индия, Германия ... Ни одно из этих значений не будет разрешено в вашем новом ENUM. Если вы пытаетесь добавить Швецию и Малайзию, сохраняя при этом исходные элементы ENUM, вам потребуется пересмотреть все исходные значения ENUM плюс 2 новых значения в вашем выражении ALTER.
Асаф
2
@Zaid Не за что. Если вы используете таблицу стран с внешним ключом вместо ENUM, как я предлагал ранее, вы сможете просто добавить строки для новых стран. КСТАТИ: Если вы нашли мои предложения полезными, пожалуйста, пометьте мой ответ правильный :)
Асаф
3
-1 Из-за отсутствия ясности о том, какое реальное решение здесь. Слишком много разговоров и много «попробуй это, ну хорошо, попробуй вместо этого». Первоначальный ответ даже не отвечает на фактический вопрос ОП - только позже вы поймете, в чем проблема, и затем вы перейдете к простым примерам кода, которые на самом деле ничего не значат для того, кто находит этот вопрос / ответ. позже. Контекст ваших правок был / был временным и больше не очевиден.
Джим Рубинштейн
73

Обсуждение я имел с Асафа может быть нечетким , чтобы следовать , как мы пошли вперед и назад совсем немного.

Я подумал, что мог бы прояснить исход нашей беседы для тех, кто может столкнуться с подобными ситуациями в будущем, чтобы извлечь выгоду из:

ENUMколоннами очень сложно управлять животными. Я хотел добавить две страны (Малайзия и Швеция) к существующему набору стран в моем ENUM.

Кажется, что MySQL 5.1 (что я и запускаю) может обновлять ENUM только путем переопределения существующего набора в дополнение к тому, что я хочу:

Это не сработало:

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

Причина заключалась в том , что заявление MySQL было заменить существующий ENUM с другой , содержащими записи 'Malaysia'и 'Sweden'только. MySQL бросил ошибку , потому что carmakeтаблица уже была ценности , как 'England'и 'USA'которые не являются частью нового ENUMопределения «s.

Удивительно, но и следующее не сработало:

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

Получается, что даже порядок элементов существующих ENUMдолжен быть сохранен при добавлении в него новых членов. Так что, если мой существующий ENUMвыглядит примерно так ENUM('England','USA'), то мой новый ENUMдолжен быть определен как ENUM('England','USA','Sweden','Malaysia')и нет ENUM('USA','England','Sweden','Malaysia'). Эта проблема проявляется только тогда, когда в существующей таблице есть записи, которые используют 'USA'или 'England'значения.

НИЖНЯЯ ГРАНИЦА:

Используйте ENUMs только тогда, когда вы не ожидаете, что ваш набор членов изменится после определения. В противном случае таблицы поиска гораздо проще обновлять и модифицировать.

Зайд
источник
Я бы рискнул укрепить итоги ... «используйте ENUM только тогда, когда вы на 100% уверены, что значения никогда не изменятся». Если таблица станет большой, будет очень трудно изменить эти значения.
DougW
6
Я не уверен, что согласен с этим итогом. Поверьте мне, мне совсем не нравятся ENUM, но я не вижу опасности в ДОБАВЛЕНИИ к возможному ENUM. По сути, ENUM - это отображение 0 -> Вариант 1, 1-> Вариант 2 и т. Д. Добавление к этому не должно вызывать проблем.
JoshStrange
2
@JoshStrange Это не столько опасность, это может быть очень неудобно, когда важен порядок вашего ENUM (например, когда используется для заказа).
1
1
Я думаю, что важно также сказать в нижней строке, что это справедливо только для старых версий MySQL, потому что, как я понимаю, с более новыми версиями проблем нет.
Никколо
Этот ответ уже не актуален, приведенный ниже должен быть помечен как принятый.
офирски
17

В версии сервера MYSQL: 5.0.27 я попробовал это, и он работал нормально для меня, проверьте вашу версию

ALTER TABLE carmake
     MODIFY `country` ENUM('Japan', 'USA', 'England', 'Australia', 'Germany', 'France', 'Italy', 'Spain', 'Czech Republic', 'China', 'South Korea', 'India', 'Sweden', 'Malaysia');
Абхишек
источник
1
Не уверен, почему это не проголосовало больше. Это просто, и это работает для меня.
наследственный
1

К сведению: полезный инструмент моделирования - phpMyAdmin с Wampserver 3.0.6 - Предварительный просмотр SQL: я использую «Предварительный просмотр SQL», чтобы увидеть код SQL, который будет сгенерирован перед сохранением столбца с изменением на ENUM. Предварительный просмотр SQL

Выше вы видите, что я ввел 'Ford', 'Toyota' в ENUM, но я получаю синтаксис ENUM (0), который генерирует синтаксическую ошибку Query error 1064 #

Затем я копирую, вставляю и изменяю SQL и запускаю его через SQL с положительным результатом.

SQL изменен

Это быстрое исправление, которое я часто использую, и его также можно использовать с существующими значениями ENUM, которые необходимо изменить. Думаю, это может быть полезно.

Адди
источник
1

Вот еще один способ ...

Он добавляет «другие» к определению перечисления столбца «rtipo» таблицы «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

Это возможно, если вы верите. Хехе. попробуйте этот код.

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

Перед добавлением нового значения

После добавления нового значения

Судья по административным делам
источник
11
Я не понимаю, как это приносит что-то новое на стол. Вопрос чисто с точки зрения MySQL. Ваш ответ включает случайный PHP, который совершенно не имеет значения, и вы не пытаетесь объяснить что-либо из этого. Бесполезный источник информации
Джонатан