Can I compare MySQL enums?
Question
I have an enumeration: ENUM( 'alpha', 'beta', 'gamma', 'delta', 'omega' )
If I sort my table by this column I get them in the correct order defined above.
However, I can't find a way to select a subset of these, e.g. everything before delta. Using WHERE status < 'delta'
only returns alpha and beta, not gamma. It seems MySQL uses a string comparison, not enum index comparison.
I could use the index numbers - i.e. WHERE status < 4
- but it's a bit of a code smell (magic numbers) and may break if I insert new values into the enumeration.
Solution
You're trying to use data-manipulation methods on metadata, and this is bound to be awkward.
This is a good reason to replace the ENUM
with a foreign key to a lookup table. Then you can use conventional data-manipulation techniques.
OTHER TIPS
You can use status+0
to return the index of the ENUM, starting from 1.
Refer http://serghei.net/docs/database/mysql/doc/E/N/ENUM.html
just came across the same issue. if you want to sort a enum field you have to cast it to a string type first (category is my enum field in the example):
SELECT
CONVERT(category USING utf8) as str_category
FROM
example
GROUP BY
str_category
ORDER BY
str_category
eazy!
You can use FIELD(column, "string1", "string2", ...)
to find rows with any particular subset of possible ENUM
values.
SELECT * FROM `table` WHERE FIELD(`enum_column`, "alpha", "delta", "et cetera");
If you want to use the range version, you can use FIND_IN_SET("needle", "hay,stack")
to return the index but you'll have to extract the ENUM list out of the table definition first with another query.
Create a function:
CREATE fEnumIndex(_table VARCHAR(50), _col VARCHAR(50), _val VARCHAR(50))
RETURNS INT DETERMINISTIC
BEGIN
DECLARE _lst VARCHAR(8192);
DECLARE _ndx INT;
SELECT REPLACE(REPLACE(REPLACE(COLUMN_TYPE,''', ''',','),'enum(',''),')','')
FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND
TABLE_NAME=_table AND COLUMN_NAME=_col INTO _lst;
SET _ndx = FIND_IN_SET(_val, _lst);
RETURN _ndx;
END
Then use it in a query as follows:
SELECT * FROM MyTable WHERE Status < fEnumIndex('MyTable','Status','delta') ;
The SELECT REPLACE(REPLACE(REPLACE(COLUMN_TYPE,''', ''',','),'enum(',''),')','')
will take the COLUMN_TYPE
such as ENUM( 'alpha', 'beta', 'gamma', 'delta', 'omega' )
and turn it into a comma-separated list: 'alpha, beta, gamma, delta, omega'
. Then the FIND_IN_SET(_val, _lst)
gets the index.
The only thing you need to be careful with is how you define the ENUMs (with or without spaces between the items) and the inner-most REPLACE
(with or without a space in the from_string).