Как я могу получить возможные значения перечисления в базе данных MySQL?


96

Я хочу автоматически заполнить свои раскрывающиеся списки возможными значениями перечисления из БД. Возможно ли это в MySQL?

Ответы:


97

У меня есть для вас версия codeigniter. Он также удаляет кавычки из значений.

function get_enum_values( $table, $field )
{
    $type = $this->db->query( "SHOW COLUMNS FROM {$table} WHERE Field = '{$field}'" )->row( 0 )->Type;
    preg_match("/^enum\(\'(.*)\'\)$/", $type, $matches);
    $enum = explode("','", $matches[1]);
    return $enum;
}

29
Это решение сломается, если сами значения перечисления содержат запятые.
Фо.

3
Это решение работает на codeigniter github.com/thiswolf/codeigniter-enum-select-boxes
You Know Nothing Джон Сноу

3
Версия PHP: $ type = $ this-> mysql-> select ("ПОКАЗАТЬ КОЛОННЫ ИЗ $ table WHERE Field = '$ field'") [0] ["Тип"];
Alessandro.Vegna

преобразовать значение типа в массив с помощью php, который я сделал следующим образом: $ сегменты = str_replace ("'", "", $ row [0] [' Type ']); $ сегменты = str_replace ("перечисление", "", $ сегменты); $ сегменты = str_replace ("(", "", $ сегменты); $ сегменты = str_replace (")", "", $ сегменты); $ segmentList = explode (',', $ сегменты);
Густаво

1
Я добавил ответ с полным доказательством извлечения всех значений перечисления, независимо от символов внутри них.
Дакусан

53

Вы можете получить значения, запросив его следующим образом:

SELECT SUBSTRING(COLUMN_TYPE,5)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='databasename' 
    AND TABLE_NAME='tablename'
    AND COLUMN_NAME='columnname'

Оттуда вам нужно будет преобразовать его в массив:

  • eval, который прямо в массив, если вы ленивы (хотя escape-последовательность MySQL в одинарных кавычках может быть несовместимой), или
  • $ options_array = str_getcsv ($ options, ',', "'"), возможно, будет работать (если вы измените подстроку, чтобы пропустить открывающие и закрывающие круглые скобки) или
  • регулярное выражение

31

Справочник по MySQL

Если вы хотите определить все возможные значения для столбца ENUM, используйте SHOW COLUMNS FROM tbl_name LIKE enum_col и проанализируйте определение ENUM в столбце Type вывода.

Вам нужно что-то вроде:

$sql = "SHOW COLUMNS FROM `table` LIKE 'column'";
$result = $db->query($sql);
$row = $result->fetchRow();
$type = $row['Type'];
preg_match('/enum\((.*)\)$/', $type, $matches);
$vals = explode(',', $matches[1]);

Это даст вам указанные значения. MySQL всегда возвращает их в одинарных кавычках. Одиночная кавычка в значении заменяется одиночной кавычкой. Вероятно, вы можете безопасно вызывать trim($val, "'")каждый из элементов массива. Вы захотите преобразовать ''в просто '.

Следующее будет возвращать элементы массива $ trimmedval без кавычек:

$trimmedvals = array();
foreach($vals as $key => $value) {
$value=trim($value, "'");
$trimmedvals[] = $value;
}

11

Это похоже на многое из вышеперечисленного, но дает результат без циклов, И дает то, что вы действительно хотите: простой массив для генерации параметров выбора.

БОНУС: работает как с полями SET, так и с ENUM.

$result = $db->query("SHOW COLUMNS FROM table LIKE 'column'");
if ($result) {
    $option_array = explode("','",preg_replace("/(enum|set)\('(.+?)'\)/","\\2", $result[0]->Type));
}

$ option_array: Array ([0] => красный [1] => зеленый [2] => синий)


10

Это одна из 8 причин, по которым тип данных MySQL ENUM является злом, названный Крисом Комленичем :

 4. Получение списка отдельных членов ENUM является сложной задачей.

Очень распространенная потребность - заполнить поле выбора или раскрывающийся список возможными значениями из базы данных. Как это:

Выберите цвет:

[ select box ]

Если эти значения хранятся в справочной таблице с именем «colors», все, что вам нужно, это: SELECT * FROM colors... которые затем можно проанализировать для динамического создания раскрывающегося списка. Вы можете добавить или изменить цвета в справочной таблице, и ваши сексуальные формы заказа будут автоматически обновлены. Потрясающие.

Теперь рассмотрим злой ENUM: как извлечь список участников? Вы можете запросить столбец ENUM в своей таблице для значений DISTINCT, но это вернет только те значения, которые фактически используются и присутствуют в таблице , а не обязательно все возможные значения. Вы можете запросить INFORMATION_SCHEMA и проанализировать их из результата запроса с помощью языка сценариев, но это излишне сложно. Фактически, я не знаю ни одного элегантного, чисто SQL-способа извлечения списка членов столбца ENUM.


9

Вы можете проанализировать строку, как если бы это была строка CSV (значения, разделенные запятыми). В PHP есть отличная встроенная функция str_getcsv, которая преобразует строку CSV в массив.

// This is an example to test with
$enum_or_set = "'blond','brunette','redhead'";

// Here is the parser
$options = str_getcsv($enum_or_set, ',', "'");

// Output the value
print_r($options);

Это должно дать вам что-то вроде следующего:

Array
(
    [0] => blond
    [1] => brunette
    [2] => redhead
)

Этот метод также позволяет использовать одинарные кавычки в ваших строках (обратите внимание на использование двух одинарных кавычек):

$enum_or_set = "'blond','brunette','red''head'";

Array
(
    [0] => blond
    [1] => brunette
    [2] => red'head
)

Дополнительные сведения о функции str_getcsv см. В руководстве по PHP: http://uk.php.net/manual/en/function.str-getcsv.php


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

2
str_getcsvработает только в PHP 5> = 5.3.0, вы можете включить этот файл, если хотите получить эту функциональность в более ранних версиях.
Стив

1
Это должен быть правильный способ обработки, поскольку он учитывает экранированные кавычки и запятые внутри строк.
Кристоффер Салл-Сторгаард,

1
Гениальное решение, экономит время;)
John

6

Более современный способ сделать это, это сработало для меня:

function enum_to_array($table, $field) {    
    $query = "SHOW FIELDS FROM `{$table}` LIKE '{$field}'";
    $result = $db->query($sql);
    $row = $result->fetchRow();
    preg_match('#^enum\((.*?)\)$#ism', $row['Type'], $matches);
    $enum = str_getcsv($matches[1], ",", "'");
    return $enum;
}

В конечном счете, значения перечисления, отделенные от enum (), представляют собой просто строку CSV, поэтому проанализируйте ее как таковую!


5

вот для mysqli

function get_enum_values($mysqli, $table, $field )
{
    $type = $mysqli->query("SHOW COLUMNS FROM {$table} WHERE Field = '{$field}'")->fetch_array(MYSQLI_ASSOC)['Type'];
    preg_match("/^enum\(\'(.*)\'\)$/", $type, $matches);
    $enum = explode("','", $matches[1]);
    return $enum;
}
$deltypevals = get_enum_values($mysqli, 'orders', 'deltype');
var_dump ($deltypevals);

4

Вот та же функция, которую дал Патрик Саваль, адаптированная для фреймворка Laravel.

function get_enum_values($table, $field)
{

   $test=DB::select(DB::raw("show columns from {$table} where field = '{$field}'"));

   preg_match('/^enum\((.*)\)$/', $test[0]->Type, $matches);
   foreach( explode(',', $matches[1]) as $value )
   {
       $enum[] = trim( $value, "'" );   
   }

   return $enum;

}

3

Для Laravel это сработало:

$result = DB::select("SHOW COLUMNS FROM `table_name` LIKE 'status';");
$regex = "/'(.*?)'/";
preg_match_all( $regex , $result[0]->Type, $enum_array );
$enum_fields = $enum_array[1];
echo "<pre>";
print_r($enum_fields);

Вывод:

Array
(
[0] => Requested
[1] => Call Back
[2] => Busy
[3] => Not Reachable
[4] => Not Responding
)

Отлично спасибо. Это сработало лучше всего для меня (Laravel 6)
Hondaman900

2

Я просто хочу добавить к тому, что говорит jasonbar , при запросе, например:

SHOW columns FROM table

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

array([0],[Field],[1],[Type],[2],[Null],[3],[Key],[4],[Default],[5],[Extra])

Где [n] и [text] дают одно и то же значение.
На самом деле не сказано в какой-либо документации, которую я нашел. Просто хорошо знать, что еще есть.


2
$row = db_fetch_object($result);
     if($row){
     $type = $row->Type;
     preg_match_all("/'([^']+)'/", $type, $matches,PREG_PATTERN_ORDER );
     return $matches[1];


}

2

попробуй это

describe table columnname

дает вам всю информацию об этом столбце в этой таблице;


2

Версия адаптации Codeigniter как метод некоторой модели:

public function enum_values($table_name, $field_name)
{
    $query = $this->db->query("SHOW COLUMNS FROM `{$table_name}` LIKE '{$field_name}'");

    if(!$query->num_rows()) return array();
    preg_match_all('~\'([^\']*)\'~', $query->row('Type'), $matches);

    return $matches[1];
}

Результат:

array(2) {
    [0]=> string(13) "administrator"
    [1]=> string(8) "customer"
}

Это не дает ответа на вопрос. Чтобы критиковать или запрашивать разъяснения у автора, оставьте комментарий под его сообщением - вы всегда можете комментировать свои собственные сообщения, и как только у вас будет достаточная репутация, вы сможете комментировать любое сообщение .
worldofjr

Ты уверен? Зачем? Результат этой функции можно просто вставить в функцию типа form_dropdown ...
Андрій Глущенко

2

Все вы используете какие-то странные и сложные шаблоны регулярных выражений x)

Вот мое решение без preg_match:

function getEnumTypes($table, $field) {
    $query = $this->db->prepare("SHOW COLUMNS FROM $table WHERE Field = ?");
    try {$query->execute(array($field));} catch (Exception $e) {error_log($e->getMessage());}
    $types = $query->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_UNIQUE, 1)[$field];
    return explode("','", trim($types, "enum()'"));
}

2

Вы можете использовать этот синтаксис для получения возможных значений перечисления в MySQL QUERY:

$syntax = "SELECT COLUMN_TYPY FROM information_schema.`COLUMNS` 
WHERE TABLE_NAME = '{$THE_TABLE_NAME}' 
AND COLUMN_NAME = '{$THE_COLUMN_OF_TABLE}'";

и вы получите значение, например: enum ('Male', 'Female')

это пример sytax php:

<?php
function ($table,$colm){

// mysql query.
$syntax = mysql_query("SELECT COLUMN_TYPY FROM information_schema.`COLUMNS` 
WHERE TABLE_NAME = '$table' AND COLUMN_NAME ='$colm'");

if (!mysql_error()){
 //Get a array possible values from table and colm.
 $array_string = mysql_fetch_array($syntax);

    //Remove part string
    $string = str_replace("'", "", $array_string['COLUMN_TYPE']);
    $string = str_replace(')', "", $string);
    $string = explode(",",substr(5,$string));
}else{
    $string = "error mysql :".mysql_error();
}
// Values is (Examples) Male,Female,Other
return $string;
}
?>

2

Проблема с каждым другим ответом в этом потоке заключается в том, что ни один из них не анализирует должным образом все особые случаи строк в перечислении.

Самым большим символом особого случая, который заставлял меня зацикливаться, были одинарные кавычки, поскольку они кодируются как две одинарные кавычки вместе! Так, например, перечисление со значением 'a'кодируется как enum('''a'''). Ужасно, правда?

Что ж, решение состоит в том, чтобы использовать MySQL для анализа данных за вас!

Поскольку все остальные используют PHP в этом потоке, я буду использовать именно его. Ниже приводится полный код. Я объясню это позже. Параметр $FullEnumStringбудет содержать всю строку перечисления, извлеченную из любого метода, который вы хотите использовать из всех других ответов. RunQuery()и FetchRow()(неассоциативный) заменяют ваши любимые методы доступа к БД.

function GetDataFromEnum($FullEnumString)
{
    if(!preg_match('/^enum\((.*)\)$/iD', $FullEnumString, $Matches))
        return null;
    return FetchRow(RunQuery('SELECT '.$Matches[1]));
}

preg_match('/^enum\((.*)\)$/iD', $FullEnumString, $Matches)подтверждает, что значение перечисления соответствует тому, что мы ожидаем, то есть "enum(".$STUFF.")"(ни до, ни после). Если preg_match терпит неудачу, NULLвозвращается.

Здесь preg_matchтакже хранится список строк, экранированных странным синтаксисом SQL, в $Matches[1]. Итак, теперь мы хотим получить из этого реальные данные. Итак, вы просто запускаете "SELECT ".$Matches[1], и у вас есть полный список строк в вашей первой записи!

Так что просто вытащите эту пластинку с FetchRow(RunQuery(...)) и все готово.

Если вы хотите сделать все это в SQL, вы можете использовать следующие

SET @TableName='your_table_name', @ColName='your_col_name';
SET @Q=(SELECT CONCAT('SELECT ', (SELECT SUBSTR(COLUMN_TYPE, 6, LENGTH(COLUMN_TYPE)-6) FROM information_schema.COLUMNS WHERE TABLE_NAME=@TableName AND COLUMN_NAME=@ColName)));
PREPARE stmt FROM @Q;
EXECUTE stmt;

PS Чтобы не дать кому-либо что-то сказать об этом, нет, я не верю, что этот метод может привести к SQL-инъекции.


Отличное решение! Конечно, это не могло быть SQL-инъекцией, потому что мы берем значения из нашей собственной схемы БД.
terales

Спасибо за подход. Я получаю повторяющиеся значения в массиве вроде этого {"building_regulations": "building_regulations", "0": "building_regulations", "list_of_owners": "list_of_owners", "1": "list_of_owners"}. Есть идеи, почему? (Хорошо работает в phpmyadmin, но это результат при запуске с использованием объекта POD.)
Guney Ozsan

Есть 3 способа получить значения из строки mysql из запроса в php. mysql_fetch_assoc извлекает значения с соответствующими ключами, mysql_fetch_row извлекает значения с числовыми ключами, а mysql_fetch_array может извлекать значения как одно или оба. Похоже, ваш pdo использует mysql_fetch_array для этой операции. Должен быть способ запретить ему делать это во время выборки.
Дакусан

Или гораздо более простой ответ на вашу проблему с pdo, просто запустите array_unique или array_filter, который удаляет числовые индексы.
Дакусан

Превосходно! Вот как вы заставляете MySQL выполнять всю тяжелую работу.
Спенсер Уильямс

2

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

SELECT
    SUBSTRING(COLUMN_TYPE, 6, LENGTH(COLUMN_TYPE) - 6) AS val
FROM
    information_schema.COLUMNS
WHERE
    TABLE_NAME = 'articles'
AND
    COLUMN_NAME = 'status'

SUBSTRINGТеперь начинается на 6 - й символ и использует длину, 6 символов короче , чем общее количество, удаляя косую скобку.


1

это сработает для меня:

SELECT REPLACE(SUBSTRING(COLUMN_TYPE,6,(LENGTH(COLUMN_TYPE)-6)),"'","")
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='__TABLE_SCHEMA__' 
AND TABLE_NAME='__TABLE_NAME__'
AND COLUMN_NAME='__COLUMN_NAME__'

а потом

explode(',', $data)

1

Для PHP 5.6+

$mysqli = new mysqli("example.com","username","password","database");
$result = $mysqli->query("SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='table_name' AND COLUMN_NAME='column_name'");
$row = $result->fetch_assoc();
var_dump($row);

1

Удивительно, но никто из вас не подумал, что если вы используете поле enum, это означает, что присваиваемые значения известны «априори».

Поэтому, если значения известны «априори», лучший способ управлять ими - использовать очень простой класс Enum.

Поцелуй правило и сохрани один вызов базы данных.

<?php
class Genre extends \SplEnum {
 const male = "Male";
 const female = "Female";
}

http://it2.php.net/manual/en/class.splenum.php


0

Я получаю значения перечисления таким образом:

SELECT COLUMN_TYPE 
FROM information_schema.`COLUMNS` 
WHERE TABLE_NAME = 'tableName' 
     AND COLUMN_NAME = 'columnName';

Запустив этот sql, я получаю: enum ('BDBL', 'AB Bank')

то я отфильтровал только значение, используя следующий код:

preg_match("/^enum\(\'(.*)\'\)$/", $type, $matches);
$enum = explode("','", $matches[1]);
var_dump($enum) ;

Вывод :

array (2) {[0] => строка (4) "BDBL" [1] => строка (7) "AB Bank"}


0
DELIMITER //

    DROP FUNCTION IF EXISTS ENUM_VALUES;

    CREATE FUNCTION ENUM_VALUES(

        _table_name VARCHAR(64), 
        _col_name VARCHAR(64)

    ) RETURNS JSON

        BEGIN

            RETURN (
                SELECT CAST(CONCAT('[', REPLACE(SUBSTRING(COLUMN_TYPE, 6, LENGTH(COLUMN_TYPE) - 6), "'", '"'), ']') AS JSON)
                  FROM information_schema.COLUMNS
                 WHERE TABLE_SCHEMA = 'db_name'
                   AND TABLE_NAME   = _table_name
                   AND COLUMN_NAME  = _col_name
                   AND DATA_TYPE    = 'enum'
            );

        END //

DELIMITER ;

Пример:

SELECT ENUM_VALUES('table_name', 'col_name');

0

ВЫБЕРИТЕ SUBSTRING (COLUMN_TYPE, 6, LENGTH (COLUMN_TYPE) - 6) AS val FROM information_schema.COLUMNS WHERE TABLE_NAME = 'article' И COLUMN_NAME = 'status'

Не работает для enum ('', 'X''XX')


1
Этот тип ответа должен быть в комментарии.
Рахул Харинхеде

Переполнение стека довольно умно и не позволяет мне комментировать из-за системы репутации.
Salvor Hardin
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.