06 февраля 2006

MySQL поля типа ENUM

ЧТО ЭТО: енум-поле представляет собой перечисление, которое изменяется крайне редко: список русских гласных, список ролей пользователей, список форматов прайс-листов, итп. Насколько я могу судить, это отход от стандарта 92 года, но очень удобный.

ЗАЧЕМ: бессмысленно делать таблицу-справочник и бесчётное число раз джойнить её с другими таблицами, если данные практически не меняются. Также енум-поле - хорошая замена хранению где-то всего списка вариантов в виде строки с последующим её распарсиванием при каждом запуске программы. БД всё это сделает за вас. Так или иначе, БД хранит где-то в своих недрах список вариантов, а в каждой вашей записи добавляется не сам элемент списка, а его порядковый номер (начиная с единицы), что есть экономия памяти, потому как элементы списка могут быть весьма длинны. Получить значение такого поля можно как в виде элемента списка, так и в виде его порядкового номера.

КАК: если вы не являетесь счастливым обладателем СУБД вроде PHPMyAdmin, то вручную добавить енум-поле можно таким запросом:

ALTER TABLE `users` ADD `role`
ENUM('guest', 'boutique', 'admin')
DEFAULT 'guest' NOT NULL;


Если вам надо получить значение этого поля, то делается это просто:


SELECT `role` FROM `users`;


Этот запрос вернёт роли пользователей в вашей
таблице в текстовом виде. Если вам надо в цифровом (порядковые номера), то можно использовать неявное приведение типа:


SELECT `role`+0 FROM `users`;


Вам может понадобиться получить РНР-массив с вариантами
этого поля для, скажем, вывода этих данных в виде листбокса.
Тогда я использую такую функцию, которой нужно передать имена таблицы и енум-поля, а на выходе получить проиндексированный
с нуля массив вариаций:

<?
function get_enum_field_values($table, $field)
{
$values = array();
$sql="SHOW COLUMNS FROM `".$table.
"` LIKE '".trim($field)."'";
$res = mysql_query($sql);
if (mysql_num_rows($res))
{
$values_t = mysql_result($res, 0, 1);

//удалить "enum(" в начале
$values_t = explode("(", $values_t);

//удалить ")" в конце
$values_t = explode(")", $values_t[1]);

//список в массив
$values = explode(",",
strtolower(trim($values_t[0])));

//удалить ковычки во всех элементах массива
array_walk($values, "del_quotes");
}
return $values;
}

//удаляет все ковычки в строке
function del_quotes(&$item1)
{
$item1=str_replace("'", "", $item1);
}

//пример использования
function get_users_roles()
{
return get_enum_field_values("users", "role");
}
?>

6 комментов:

Dmitry Kalabin комментирует...

. мне почему-то кажется, что PHPMyAdmin еще не дорасло до того чтобы быть СУБД. ;)
2. foreign key с другой таблицы на ENUM поле - как работает и есть ли выгоды?
3. если все же понадобилось добавить новые значения в набор после создания колонки для таблицы уже набитой данными - можно ли такое вообще? не поменяет ли сервер при этом маппинг исходных цифровых значений в буквенные, из-за чего все исходные данные пойдут курить лесом?
4. если надо в другой таблице создать поле ENUM с абсолютно таким же набором значений и обеспечить синхронное состояник наборов - что будем делать?

A4 комментирует...

1. Я знал, что кто-то поправит :]
Учитывая, что лично я использую систему PHPMyAdmin для управления базами данных, я окрестил её СУБД. Сознательно и буквально.
2. К моему глубокому сожалению, foreign key не работает в MySQL, поэтому сказать не могу. Жду с релиза на релиз, потому что следить за целостностью данных вручную - неудобно. Да, InnoDB в MySQL умеет их, но я не использую InnoDB, поэтому пока ку-ку.
3. Проверил - добавил сначала в конец, потом в середину списка - сервер всё перемапил, умница. А я было испугался. Страшные ты вещи спрашиваешь, Дима, хотя и логичные.
4. Нууу... Если так ставить вопрос, то я бы сделал отдельный справочник. Енум на то и енум, что он отражает атрибут какого-то одного объекта - у меня это пока уровни пользователей в таблице пользователей и форматы загружаемых прайс-листов в таблице прайс-листов; все они динамически не редактируются, потому как мало добавить роль пользователя, нужно под неё логику запрогать. Для таких целей енум подходит идеально.

GIN комментирует...

а почему не используете InnoDB? Удобно вроде как. Ну да, полнотекстового поиска не будет, но его можно руками сымитировать. Да и Sphinx можно прикрутить вообще, если сервак свой.

А4 комментирует...

Уже использую. Foreign key оказались нужны вообще во ВСЕХ проектах, а полнотекстовый поиск только в очень некоторых.

Артём комментирует...

Вот тут заинтересовался недавно этим типом.
Погуглил, поспрашивал - толком никто ничего не знает, мало кто использовал.
Провёл собственные тесты.
Результаты далеко не в пользу ENUM - проигрывает по производительности foreign key раза в 3 :)

Маргарита комментирует...

код совсем некорректный, зачем все так усложнять
и слздавать функции, если можно удалить каычки одни оператором до массива вообще в сотни раз медленен и не эфективней скрипт...

http://www.2828.ru/


function mb($m){ # значение всех ENUM
return explode(",",str_replace(array("'",")"),"",substr(mysql_result(mysql_query('DESCRIBE `MX-TBL` '.$m),0,1),5)));
}

http://www.2828.ru/vip/code

Отправить комментарий