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.

Was it helpful?

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).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top