ENUM
Why ENUM?
Section titled “Why ENUM?”ENUM provides a way to provide an attribute for a row. Attributes with a small number of non-numeric options work best. Examples:
reply ENUM('yes', 'no')gender ENUM('male', 'female', 'other', 'decline-to-state')The values are strings:
INSERT ... VALUES ('yes', 'female')SELECT ... --> yes femaleVARCHAR as an alternative
Section titled “VARCHAR as an alternative”Let’s say we have
type ENUM('fish','mammal','bird')An alternative is
type VARCHAR(20) COMENT "fish, bird, etc"This is quite open-ended in that new types are trivially added.
Comparison, and whether better or worse than ENUM:
- (same) INSERT: simply provide the string
- (worse?) On INSERT a typo will go unnoticed
- (same) SELECT: the actual string is returned
- (worse) A lot more space is consumed
Adding a new option
Section titled “Adding a new option”ALTER TABLE tbl MODIFY COLUMN type ENUM('fish','mammal','bird','insect');Notes
- As with all cases of MODIFY COLUMN, you must include
NOT NULL, and any other qualifiers that originally existed, else they will be lost. - If you add to the end of the list and the list is under 256 items, the
ALTERis done by merely changing the schema. That is there will not be a lengthy table copy. (Old versions of MySQL did not have this optimization.)
NULL vs NOT NULL
Section titled “NULL vs NOT NULL”Examples of what happens when NULL and ‘bad-value’ are stored into nullable and not nullable columns. Also shows usage of casting to numeric via +0.
CREATE TABLE enum ( e ENUM('yes', 'no') NOT NULL, enull ENUM('x', 'y', 'z') NULL );INSERT INTO enum (e, enull) VALUES ('yes', 'x'), ('no', 'y'), (NULL, NULL), ('bad-value', 'bad-value');Query OK, 4 rows affected, 3 warnings (0.00 sec)Records: 4 Duplicates: 0 Warnings: 3
mysql>SHOW WARNINGS;+---------+------+--------------------------------------------+| Level | Code | Message |+---------+------+--------------------------------------------+| Warning | 1048 | Column 'e' cannot be null || Warning | 1265 | Data truncated for column 'e' at row 4 || Warning | 1265 | Data truncated for column 'enull' at row 4 |+---------+------+--------------------------------------------+3 rows in set (0.00 sec)What is in the table after those inserts. This uses “+0” to cast to numeric see what is stored.
mysql>SELECT e, e+0 FROM enum;+-----+-----+| e | e+0 |+-----+-----+| yes | 1 || no | 2 || | 0 | -- NULL| | 0 | -- 'bad-value'+-----+-----+4 rows in set (0.00 sec)
mysql>SELECT enull, enull+0 FROM enum;+-------+---------+| enull | enull+0 |+-------+---------+| x | 1 || y | 2 || NULL | NULL || | 0 | -- 'bad-value'+-------+---------+4 rows in set (0.00 sec)TINYINT as an alternative
Section titled “TINYINT as an alternative”Let’s say we have
type ENUM('fish','mammal','bird')An alternative is
type TINYINT UNSIGNEDplus
CREATE TABLE AnimalTypes ( type TINYINT UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(20) NOT NULL COMMENT "('fish','mammal','bird')", PRIMARY KEY(type), INDEX(name)) ENGINE=InnoDBwhich is very much like a many-to-many table.
Comparison, and whether better or worse than ENUM:
- (worse) INSERT: need to lookup the
type - (worse) SELECT: need to JOIN to get the string (ENUM gives you the string with no effort)
- (better) Adding new types: Simply insert into this table. With ENUM, you need to do an ALTER TABLE.
- (same) Either technique (for up to 255 values) takes only 1 byte.
- (mixed) There’s also an issue of data integrity:
TINYINTwill admit invalid values; whereasENUMsets them to a special empty-string value (unless strict SQL mode is enabled, in which case they are rejected). Better data integrity can be achieved withTINYINTby making it a foreign key into a lookup table: which, with appropriate queries/joins, but there is still the small cost of reaching into the other table. (FOREIGN KEYsare not free.)