views:

965

answers:

2

The MySQL reference manual does not provide a clearcut example on how to do this.

I have an ENUM-type column of country names that I need to add more countries to. What is the correct MySQL syntax to achieve this?

Here's my attempt:

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

The error I get is: ERROR 1265 (01000): Data truncated for column 'country' at row 1.

The country column is the ENUM-type column in the above-statement.

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)

SELECT DISTINCT country FROM carmake OUTPUT:

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

Your code works for me. Here is my test case:

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)

What error are you seeing?

FWIW this would also work:

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

I would actually recommend a country table rather than enum column. You may have hundreds of countries which would make for a rather large and awkward enum.

EDIT: Now that I can see your error message:

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

I suspect you have some values in your country column that do not appear in your ENUM. What is the output of the following command?

SELECT DISTINCT country FROM carmake;

ANOTHER EDIT: What is the output of the following command?

SHOW VARIABLES LIKE 'sql_mode';

Is it STRICT_TRANS_TABLES or STRICT_ALL_TABLES? That could lead to an error (rather than the usual warning MySQL would give you in this situation.

YET ANOTHER EDIT: Ok, I now see that you definitely have values in the table that are not in the new ENUM. The new ENUM definition only allows 'Sweden' and 'Malaysia'. The table has 'USA', 'India' and several others.

LAST EDIT (MAYBE): I think you're trying to do this:

ALTER TABLE carmake CHANGE country country ENUM('Italy', 'Germany', 'England', 'USA', 'France', 'South Korea', 'Australia', 'Spain', 'Czech Republic', 'Sweden', 'Malaysia') DEFAULT NULL;
Asaph
There's more than one column in my `carmake` table. Could that have anything to do with it?
Zaid
Unlikely but post the output of this command "SHOW CREATE TABLE carmake" and I'll look at it.
Asaph
@Zaid I see you've added the error message "The error I get is: ERROR 1265 (01000): Data truncated for column 'country' at row 1.". I think the problem is that you have values already in the country column that are not listed in the enum.
Asaph
That's not the case. The ENUM type doesn't allow for entries that are not present in the ENUM itself. My table is about 50 entries at the moment. At a glance, I can tell you that no invalid values are present.
Zaid
@Zaid be careful about saying that. MySQL is notorious for allowing garbage into ENUM columns. It will silently convert non-conforming values to empty strings, for instance. Are you 100% sure you don't have any offending values? No empty strings? No leading or trailing whitespace? Case differences? Accented characters?
Asaph
@Asaph: The `SHOW VARIABLES LIKE 'sql_mode';` command returns `STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION`. What does that mean?
Zaid
@Asaph: I've updated the OP, no erroneous values.
Zaid
@Zaid I think you do have values in your table that are absent from your updated ENUM definition. Your new definition only allows Sweden and Malaysia. Your table has USA, India, Germany... None of those values will be allowed in your new ENUM. If what you are trying to do is *add* Sweden and Malaysia while preserving the original members of the ENUM, you'll need to relist *all* the original ENUM values plus the 2 new ones in your ALTER statement.
Asaph
@Asaph: That's a bummer. I was hoping that for a way to append to the existing list. Thanks for your help anyway. I really appreciate it.
Zaid
@Zaid You're welcome. If you use a countries table with a foreign key instead of the ENUM as I suggested early on, you'll be able to simply add rows for the new countries. BTW: If you've found my suggestions helpful, please mark my answer correct :)
Asaph
@Asaph: I have every intention of maintaining my 100% acceptance rate. I'd just like to leave the question open to other SO users to see if there is a way to append to the existing enum set, so I'll accept it after a few hours. I've uprated your answer though as it has been quite insightful into MySQL debugging.
Zaid
Perhaps you could combine this with a query of the existing enum members.
Svante
@Asaph: I originally chose to go with this ENUM type because I wanted to avoid the hassle of having to deal with stray/duplicate entries. I had no idea ENUMs were this unwieldy...
Zaid
A: 

The discussion I had with Asaph may be unclear to follow as we went back and forth quite a bit.

I thought that I might clarify the upshot of our discourse for others who might face similar situations in the future to benefit from:

ENUM-type columns are very difficult beasts to manipulate. I wanted to add two countries (Malaysia & Sweden) to the existing set of countries in my ENUM.

It seems that MySQL 5.1 (which is what I am running) can only update the ENUM by redefining the existing set in addition to what I want:

This did not work:

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

The reason was that the MySQL statement was replacing the existing ENUM with another containing the entries 'Malaysia' and 'Sweden' only. MySQL threw up an error because the carmake table already had values like 'England' and 'USA' which were not part of the new ENUM's definition.

Surprisingly, the following did not work either:

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

It turns out that even the order of elements of the existing ENUM needs to be preserved while adding new members to it. So if my existing ENUM looks something like ENUM('England','USA'), then my new ENUM has to be defined as ENUM('England','USA','Sweden','Malaysia') and not ENUM('USA','England','Sweden','Malaysia'). This problem only becomes manifest when there are records in the existing table that use 'USA' or 'England' values.

BOTTOM LINE:

Only use ENUMs when you do not expect your set of members to change once defined. Otherwise, lookup tables are much easier to update and modify.

Zaid