5

In a web application, I need to populate a <select> with all possible values of a MySQL enum.

When I execute either of:

SHOW COLUMNS FROM  mytable LIKE  'mycolumn';
SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = 'mytable' AND COLUMN_NAME = 'mycolumn';
I always end up with enum('valueA','valueB','valueC').

I know I can parse it with PHP but can it be done using SQL only? I need something like this:

+-----------------+
| values          |
+-----------------+
| valueA          |
| valueB          |
| valueC          |
+-----------------+
1

3 Answers 3

7

This is one of Chris Komlenic's 8 Reasons Why MySQL's ENUM Data Type Is Evil:

 4. Getting a list of distinct ENUM members is a pain.

A very common need is to populate a select-box or drop down list with possible values from the database. Like this:

Select color:

[ select box ]

If these values are stored in a reference table named 'colors', all you need is: SELECT * FROM colors ...which can then be parsed out to dynamically generate the drop down list. You can add or change the colors in the reference table, and your sexy order forms will automatically be updated. Awesome.

Now consider the evil ENUM: how do you extract the member list? You could query the ENUM column in your table for DISTINCT values but that will only return values that are actually used and present in the table, not necessarily all possible values. You can query INFORMATION_SCHEMA and parse them out of the query result with a scripting language, but that's unnecessarily complicated. In fact, I don't know of any elegant, purely SQL way to extract the member list of an ENUM column.

Sign up to request clarification or add additional context in comments.

1 Comment

Ugh, this is what I was afraid of.
4

While I would agree about not using enums most of the time, it is possible in a single SQL statement:-

SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING(COLUMN_TYPE, 7, LENGTH(COLUMN_TYPE) - 8), "','", 1 + units.i + tens.i * 10) , "','", -1)
FROM INFORMATION_SCHEMA.COLUMNS
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
WHERE TABLE_NAME = 'mytable' 
AND COLUMN_NAME = 'mycolumn'

This will work for enums with up to 100 possible values

6 Comments

What if one or more values contain ','? See sqlfiddle.
It would cause problems, although can be dealt with by replacing the embeded ',' (stored as '','') and a few other faffs. Either way it is possible, even if a good reason to avoid using enums.
Thank you so much! I knew there had to be a way, although my SQL skills are not developed enough to find it myself. And yes, I totally agree with not using enums, but sometimes you can't change how the current system is built.
It is possible, but I would suggest that if you can you amend your tables to avoid the use of enums. My code above is not likely to be quick and not something I would want to use on any generally used page. Possibly better to use it to extract the values to populate table(s) of the possible values which the system can be modified to use instead.
@gumgl: I suppose the more general observation is that, if the possible values are embedded in the database schema (as they are in the definition of an ENUM column), then they may as well be embedded in one's code too. A change of schema invariably requires a change of codebase. If one is reluctant to embed the options into one's code, it indicates that they are expected to change / intended to be dynamic - in which case ENUM is entirely the wrong datatype to use in the first place.
|
0

This is the simplest solution

$EnumColum = $mysqli->query(
  $link,
  "SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = 'mrb_shipping_carriers' AND COLUMN_NAME = 'uspsServiceType'"
) or die("Error in " . ": " . __FILE__ . ": " . __LINE__);

$replace1 = preg_replace("/enum/", '',$EnumColum[0]['COLUMN_TYPE']);
$replace2 = preg_replace("/\(/", '',$replace1);
$replace3 = preg_replace("/\)/", '',$replace2);
$replace4 = preg_replace("/\'/", '',$replace3);
$newArray = explode(',',$replace4);
foreach($newArray as $value){
    echo $value . "\n<br>";
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.