Я хочу автоматически заполнить свои раскрывающиеся списки возможными значениями перечисления из БД. Возможно ли это в MySQL?
Ответы:
У меня есть для вас версия 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;
}
Вы можете получить значения, запросив его следующим образом:
SELECT SUBSTRING(COLUMN_TYPE,5)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='databasename'
AND TABLE_NAME='tablename'
AND COLUMN_NAME='columnname'
Оттуда вам нужно будет преобразовать его в массив:
Если вы хотите определить все возможные значения для столбца 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;
}
Это похоже на многое из вышеперечисленного, но дает результат без циклов, И дает то, что вы действительно хотите: простой массив для генерации параметров выбора.
БОНУС: работает как с полями 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] => синий)
Это одна из 8 причин, по которым тип данных MySQL ENUM является злом, названный Крисом Комленичем :
4. Получение списка отдельных членов ENUM является сложной задачей.
Очень распространенная потребность - заполнить поле выбора или раскрывающийся список возможными значениями из базы данных. Как это:
Выберите цвет:
[ select box ]
Если эти значения хранятся в справочной таблице с именем «colors», все, что вам нужно, это:
SELECT * FROM colors
... которые затем можно проанализировать для динамического создания раскрывающегося списка. Вы можете добавить или изменить цвета в справочной таблице, и ваши сексуальные формы заказа будут автоматически обновлены. Потрясающие.Теперь рассмотрим злой ENUM: как извлечь список участников? Вы можете запросить столбец ENUM в своей таблице для значений DISTINCT, но это вернет только те значения, которые фактически используются и присутствуют в таблице , а не обязательно все возможные значения. Вы можете запросить INFORMATION_SCHEMA и проанализировать их из результата запроса с помощью языка сценариев, но это излишне сложно. Фактически, я не знаю ни одного элегантного, чисто SQL-способа извлечения списка членов столбца ENUM.
Вы можете проанализировать строку, как если бы это была строка 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
str_getcsv
работает только в PHP 5> = 5.3.0, вы можете включить этот файл, если хотите получить эту функциональность в более ранних версиях.
Более современный способ сделать это, это сработало для меня:
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, поэтому проанализируйте ее как таковую!
вот для 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);
Вот та же функция, которую дал Патрик Саваль, адаптированная для фреймворка 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;
}
Для 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
)
Я просто хочу добавить к тому, что говорит jasonbar , при запросе, например:
SHOW columns FROM table
Если вы получите результат в виде массива, он будет выглядеть так:
array([0],[Field],[1],[Type],[2],[Null],[3],[Key],[4],[Default],[5],[Extra])
Где [n] и [text] дают одно и то же значение.
На самом деле не сказано в какой-либо документации, которую я нашел. Просто хорошо знать, что еще есть.
$row = db_fetch_object($result);
if($row){
$type = $row->Type;
preg_match_all("/'([^']+)'/", $type, $matches,PREG_PATTERN_ORDER );
return $matches[1];
}
попробуй это
describe table columnname
дает вам всю информацию об этом столбце в этой таблице;
Версия адаптации 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"
}
Все вы используете какие-то странные и сложные шаблоны регулярных выражений 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()'"));
}
Вы можете использовать этот синтаксис для получения возможных значений перечисления в 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;
}
?>
Проблема с каждым другим ответом в этом потоке заключается в том, что ни один из них не анализирует должным образом все особые случаи строк в перечислении.
Самым большим символом особого случая, который заставлял меня зацикливаться, были одинарные кавычки, поскольку они кодируются как две одинарные кавычки вместе! Так, например, перечисление со значением '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-инъекции.
Чтобы получить список возможных значений, был хорошо документирован, но, расширяя другой ответ, который возвращал значения в круглых скобках , я хотел удалить их, оставив мне список, разделенный запятыми, который затем позволил бы мне использовать функцию типа разнесения всякий раз, когда я нужно было получить массив.
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 символов короче , чем общее количество, удаляя косую скобку.
Для 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);
Удивительно, но никто из вас не подумал, что если вы используете поле enum, это означает, что присваиваемые значения известны «априори».
Поэтому, если значения известны «априори», лучший способ управлять ими - использовать очень простой класс Enum.
Поцелуй правило и сохрани один вызов базы данных.
<?php
class Genre extends \SplEnum {
const male = "Male";
const female = "Female";
}
Я получаю значения перечисления таким образом:
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"}
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');
ВЫБЕРИТЕ SUBSTRING (COLUMN_TYPE, 6, LENGTH (COLUMN_TYPE) - 6) AS val FROM information_schema.COLUMNS WHERE TABLE_NAME = 'article' И COLUMN_NAME = 'status'
Не работает для enum ('', 'X''XX')