【发布时间】:2011-01-21 22:41:13
【问题描述】:
我想用数据库中的枚举可能值自动填充我的下拉列表。这在 MySQL 中可行吗?
【问题讨论】:
我想用数据库中的枚举可能值自动填充我的下拉列表。这在 MySQL 中可行吗?
【问题讨论】:
如果你想确定所有可能的 ENUM 列的值,使用 SHOW 来自 tbl_name 的列,如 enum_col 并解析 ENUM 中的定义 输出的类型列。
你会想要这样的东西:
$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, "'")。您需要将 '' 转换为 '。
以下将返回不带引号的 $trimmedvals 数组项:
$trimmedvals = array();
foreach($vals as $key => $value) {
$value=trim($value, "'");
$trimmedvals[] = $value;
}
【讨论】:
我只是想在查询时添加 jasonbar 所说的内容:
SHOW columns FROM table
如果您将结果作为数组输出,它将如下所示:
array([0],[Field],[1],[Type],[2],[Null],[3],[Key],[4],[Default],[5],[Extra])
其中 [n] 和 [text] 给出相同的值。
在我找到的任何文档中都没有真正说明。很高兴知道还有什么。
【讨论】:
您可以通过这样的查询来获取值:
SELECT SUBSTRING(COLUMN_TYPE,5)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='databasename'
AND TABLE_NAME='tablename'
AND COLUMN_NAME='columnname'
从那里你需要将它转换成一个数组:
【讨论】:
$row = db_fetch_object($result);
if($row){
$type = $row->Type;
preg_match_all("/'([^']+)'/", $type, $matches,PREG_PATTERN_ORDER );
return $matches[1];
}
【讨论】:
您可以将字符串解析为 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,如果您想在早期版本中获得此功能,您可以include this file。
我为你准备了一个 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;
}
【讨论】:
试试这个
describe table columnname
为您提供有关该表中该列的所有信息;
【讨论】:
这是 Chris Komlenic 的 8 Reasons Why MySQL's ENUM Data Type Is Evil 之一:
4. 获取不同 ENUM 成员的列表很麻烦。
一个非常常见的需求是使用数据库中的可能值填充选择框或下拉列表。像这样:
选择颜色:
[ select box ]如果这些值存储在名为“colors”的引用表中,您只需要:
SELECT * FROM colors...然后可以将其解析出来以动态生成下拉列表。您可以在参考表中添加或更改颜色,您的性感订单表格将自动更新。太棒了。现在考虑邪恶的 ENUM:如何提取成员列表?您可以在表中的 ENUM 列中查询 DISTINCT 值,但这只会返回实际使用并存在于表中的值,不一定是所有可能的值。您可以查询 INFORMATION_SCHEMA 并使用脚本语言将它们从查询结果中解析出来,但这不必要地复杂。事实上,我不知道有什么优雅的、纯 SQL 的方法来提取 ENUM 列的成员列表。
【讨论】:
一种更新的方式,这对我有用:
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 字符串,所以就这样解析吧!
【讨论】:
这与上面的很多内容类似,但为您提供不带循环的结果,并得到您真正想要的:一个用于生成选择选项的简单数组。
奖励:它适用于 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: 大批 ( [0] => 红色 [1] => 绿色 [2] => 蓝色 )
【讨论】:
这是 Patrick Savalle 为框架 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;
}
【讨论】:
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()'"));
}
【讨论】:
这对我有用:
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)
【讨论】:
您可以使用此语法在 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')
这是 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;
}
?>
【讨论】:
这里是 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 有效:
$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
)
【讨论】:
我以这种方式获取枚举值:
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]=>
string(4) "BDBL"
[1]=>
string(7) "AB Bank"
}
【讨论】:
此线程中所有其他答案的问题在于,它们都没有正确解析枚举中字符串的所有特殊情况。
让我陷入循环的最大特例字符是单引号,因为它们本身被编码为 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 还将字符串列表存储在$Matches[1] 中,以奇怪的SQL 语法进行转义。所以接下来,我们希望能够从中获取真实数据。因此,您只需运行 "SELECT ".$Matches[1],就可以在第一条记录中获得完整的字符串列表!
因此,只需使用 FetchRow(RunQuery(...)) 提取该记录即可。
如果你想在 SQL 中完成这整个事情,你可以使用下面的
SET @TableName='your_table_name', @ColName='your_col_name', @DBName='your_database_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 AND TABLE_SCHEMA=@DBName)));
PREPARE stmt FROM @Q;
EXECUTE stmt;
附:抢先阻止任何人对此发表评论,不,我不相信这种方法会导致 SQL 注入。
【讨论】:
要获取可能值的列表已经有很好的记录,但是expanding on another answer that returned the values in parenthesis,我想把它们去掉,留下一个逗号分隔的列表,这样我就可以在需要时使用爆炸类型的函数来获取数组。
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);
【讨论】:
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');
【讨论】:
奇怪的是,你们都没有想到,如果您使用枚举字段,这意味着要分配的值是“先验的”。
因此,如果这些值是“先验”已知的,那么管理它们的最佳方法是通过一个非常简单的 Enum 类。
Kiss 规则并保存一个数据库调用。
<?php
class Genre extends \SplEnum {
const male = "Male";
const female = "Female";
}
【讨论】:
SELECT
SUBSTRING(COLUMN_TYPE, 6, LENGTH(COLUMN_TYPE) - 6) AS val
FROM
information_schema.COLUMNS
WHERE
TABLE_NAME = 'articles'
AND
COLUMN_NAME = 'status'
不适用于枚举('','X''XX')
【讨论】:
这是自定义 WordPress 表格的解决方案。这适用于没有逗号 (,) 的 ENUM 值
function get_enum_values($wpdb, $table, $field) {
$values = array();
$table = "{$wpdb->prefix}{$table}";
$query = "SHOW COLUMNS FROM {$table} WHERE Field = '{$field}'";
$results = $wpdb->get_results($query, ARRAY_A);
if (is_array($results) && count($results) > 0) {
preg_match("/^enum\(\'(.*)\'\)$/", $results[0]['Type'], $matches);
if (is_array($matches) && isset($matches[1])) {
$values = explode("','", $matches[1]);
}
}
return $values;
}
【讨论】:
添加到 cchana 的答案。方法“length-6”在枚举中的非拉丁值上失败。
例如(值是西里尔文,表是 UTF8 - utf8_general_ci。在示例中,为了简单起见,我使用变量:从模式中选择给出相同的值):
set @a:="enum('в работе','на списание','списано')";
select substring(@a,6,length(@a)-6);
+-------------------------------------------------------------+
| substring(@a,6,length(@a)-6) |
+-------------------------------------------------------------+
| 'в работе','на списание','списано') |
+-------------------------------------------------------------+
注意右括号?
select right(@a,1);
+-------------+
| right(@a,1) |
+-------------+
| ) |
+-------------+
好吧,让我们再删除一个字符:
select substring(@a,6,length(@a)-7);
+-------------------------------------------------------------+
| substring(@a,6,length(@a)-7) |
+-------------------------------------------------------------+
| 'в работе','на списание','списано') |
+-------------------------------------------------------------+
不走运!括号保持不变。
检查(mid() 函数的工作方式与substring() 类似,两者显示相同的结果):
select mid(@a,6,length(@a)/2);
+---------------------------------------------------------+
| mid(@a,6,length(@a)/2) |
+---------------------------------------------------------+
| 'в работе','на списание','списан |
+---------------------------------------------------------+
请看:字符串只丢失了最右边的三个字符。但是我们是否应该用拉丁文替换西里尔文,并且一切都完美无缺:
set @b:="enum('in use','for removal','trashed')";
select (substring(@b,6,length(@b)-6));
+----------------------------------+
| (substring(@b,6,length(@b)-6)) |
+----------------------------------+
| 'in use','for removal','trashed' |
+----------------------------------+
仅供参考
编辑20210221:非拉丁字符的解决方案是CHAR_LENGTH()而不是“简单”LENGTH()
【讨论】:
这将使用 PDO:
$stmt = $mysql->prepare("SHOW COLUMNS FROM table LIKE 'column'");
$stmt->execute();
$enumvalues = $stmt->fetch(PDO::FETCH_ASSOC)['Type'];
$enumvalues = explode(',', str_replace('\'', '', substr($enumvalues, 5, strlen($enumvalues) - 6)));
【讨论】: