如何在MySQL的ENUM类型列中添加更多成员?


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)

从carmake输出中选择不同的国家/地区

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

Answers:


134
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做到这一点?
约翰(John John)

枚举只是一个花哨的整数,带有字符串表示形式。在末尾添加项目就可以了,因为您只需添加有意义的旧值即可。但是更改顺序/删除枚举将使这些数字不确定。(例如1 =>意大利,2 =>德国),则扩展将是(1 =>意大利,2 =>德国,3 =>中间人)。
lintabá

1
@John视情况而定。对于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');

我实际上会建议使用国家/地区表而不是枚举列。您可能有数百个国家/地区,这些国家可能会导致相当大且尴尬的枚举。

编辑:现在,我可以看到您的错误信息:

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会向您发出通常的警告。

再次编辑:好的,我现在看到您的表格中肯定有不在new中的值ENUM。新的ENUM定义仅允许'Sweden''Malaysia'。该表具有'USA''India'和其他几个人。

最后编辑(MAYBE):我认为您正在尝试这样做:

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

我的carmake表格中有不止一列。可以和它有什么关系吗?
扎伊德

1
@Zaid谨慎地说。MySQL因允许垃圾进入ENUM列而臭名昭著。例如,它将以静默方式将不合格的值转换为空字符串。您是否100%确定没有任何违规值?没有空字符串?没有前导或尾随空格?大小写不同?重音符号?
Asaph,2009年

1
@Zaid我认为您的表中确实有更新的ENUM定义中缺少的值。您的新定义仅允许瑞典和马来西亚。您的表格有美国,印度,德国...在新的ENUM中将不允许使用这些值。如果您要在保留ENUM原始成员的同时添加瑞典和马来西亚,则需要在ALTER语句中重新列出所有原始ENUM值以及2个新值。
Asaph

2
@Zaid不客气。如果您使用带外键的国家/地区表而不是我早先建议的ENUM,则可以为新国家/地区简单地添加行。顺便说一句:如果您发现我的建议有用,请标记我的答案正确:)
Asaph

3
-1由于不清楚此处的实际解决方案。讨论太多,“尝试一下,好吧,尝试一下”。最初的回答甚至没有回答OP的实际问题-直到后来您才意识到问题所在,然后进入简单的代码示例,这些示例对于发现此问题/答案的人实际上没有任何意义晚些时候。您所做编辑的上下文是暂时的,不再明显。
Jim Rubenstein 2014年

73

我和Asaph进行的讨论可能不清楚,因为我们来回反复了很多。

我认为我可以为其他将来可能会遇到类似情况的人澄清我们的话语结果,以从中受益:

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'它们都不是new ENUM定义的一部分。

令人惊讶的是,以下方法也不起作用:

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')and而不是ENUM('USA','England','Sweden','Malaysia')。仅当现有表中有使用'USA''England'值的记录时,此问题才会变得明显。

底线:

ENUM在不希望成员组一旦定义就更改的情况下使用。否则,查找表更容易更新和修改。


我会冒险提出一个更强的底线...“仅当您100%死亡时才使用ENUM,肯定这些值永远不会改变”。如果表变大,则必须更改这些值会很痛苦。
DougW

6
我不确定我是否同意这一底线。相信我,我一点都不喜欢ENUM,但我看不到增加可能的ENUM的危险。ENUM的核心是0->选项1、1->选项2等的映射。添加该映射不会引起问题。
JoshStrange 2015年

2
@JoshStrange并没有太大的危险,当您的ENUM顺序很重要时(例如,用于订购时)可能会带来极大的不便。
1in9ui5t 2015年

1
我认为重要的是,在底线中说这仅对旧版本的MySQL有效,因为就我所知,对于较新的版本,这没有问题。
尼可罗马基

该答案不再适用,以下标记为已接受。
ofirski '18年

16

在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

仅供参考:一种有用的模拟工具-带有Wampserver 3.0.6的phpMyAdmin-预览SQL:在保存更改为ENUM的列之前,我使用“预览SQL”来查看将要生成的SQL代码。 预览SQL

在上面的代码中,我已经在ENUM中输入了“ Ford”,“ Toyota”,但我正在获取语法ENUM(0),该语法生成​​语法错误查询错误1064#

然后,我复制,粘贴和更改SQL,并通过SQL运行它,结果是肯定的。

SQL已更改

这是我经常使用的快速修复,也可以用于需要更改的现有ENUM值。认为这可能有用。


1

这是另一种方式

它将“其他”添加到表“ firmas”的列“ rtipo”的枚举定义中。

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,并且您不会尝试对其进行任何解释。无用的信息资源
乔纳森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.