【问题标题】:How can I get enum possible values in a MySQL database?如何在 MySQL 数据库中获取枚举可能值?
【发布时间】:2011-01-21 22:41:13
【问题描述】:

我想用数据库中的枚举可能值自动填充我的下拉列表。这在 MySQL 中可行吗?

【问题讨论】:

    标签: php mysql


    【解决方案1】:

    MySQL Reference

    如果你想确定所有可能的 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;
    }
    

    【讨论】:

      【解决方案2】:

      我只是想在查询时添加 jasonbar 所说的内容:

      SHOW columns FROM table
      

      如果您将结果作为数组输出,它将如下所示:

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

      其中 [n] 和 [text] 给出相同的值。
      在我找到的任何文档中都没有真正说明。很高兴知道还有什么。

      【讨论】:

        【解决方案3】:

        您可以通过这样的查询来获取值:

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

        从那里你需要将它转换成一个数组:

        • 如果你是懒惰的,直接评估它到一个数组中(尽管 MySQL 的单引号转义可能不兼容),或者
        • $options_array = str_getcsv($options, ',', "'") 可能会起作用(如果您更改子字符串以跳过左括号和右括号),或者
        • 正则表达式

        【讨论】:

          【解决方案4】:
          $row = db_fetch_object($result);
               if($row){
               $type = $row->Type;
               preg_match_all("/'([^']+)'/", $type, $matches,PREG_PATTERN_ORDER );
               return $matches[1];
          
          
          }
          

          【讨论】:

            【解决方案5】:

            您可以将字符串解析为 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
            • 这应该是处理它的正确方法,因为它考虑了字符串中的转义引号和逗号。
            • 出色的解决方案,节省时间 ;)
            【解决方案6】:

            我为你准备了一个 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;
            }
            

            【讨论】:

            • 如果枚举值本身包含逗号,此解决方案将中断。
            • 此解决方案适用于 codeigniter github.com/thiswolf/codeigniter-enum-select-boxes
            • PHP 版本:$type = $this->mysql->select("SHOW COLUMNS FROM $table WHERE Field = '$field'")[0]["Type"];
            • 使用 php 将类型值转换为数组我是这样制作的: $segments = str_replace("'", "", $row[0]['Type']); $segments = str_replace("枚举", "", $segments); $segments = str_replace("(", "", $segments); $segments = str_replace(")", "", $segments); $segmentList = explode(',', $segments);
            • 我已经添加了an answer 一个完整的证明方法来提取所有枚举值,无论它们里面的字符是什么。
            【解决方案7】:

            试试这个

            describe table columnname
            

            为您提供有关该表中该列的所有信息;

            【讨论】:

              【解决方案8】:

              这是 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 列的成员列表。

              【讨论】:

                【解决方案9】:

                一种更新的方式,这对我有用:

                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 字符串,所以就这样解析吧!

                【讨论】:

                  【解决方案10】:

                  这与上面的很多内容类似,但为您提供不带循环的结果,并得到您真正想要的:一个用于生成选择选项的简单数组。

                  奖励:它适用于 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] => 蓝色 )

                  【讨论】:

                    【解决方案11】:

                    这是 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;
                    
                    }
                    

                    【讨论】:

                      【解决方案12】:

                      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"
                      }
                      

                      【讨论】:

                      • 这并没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方发表评论 - 您可以随时评论自己的帖子,一旦您有足够的reputation,您就可以comment on any post
                      • 你确定吗?为什么?此函数的结果可以简单地插入到 form_dropdown... 之类的函数中
                      【解决方案13】:

                      你们都使用了一些奇怪而复杂的正则表达式 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()'"));
                      }
                      

                      【讨论】:

                        【解决方案14】:

                        这对我有用:

                        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)
                        

                        【讨论】:

                          【解决方案15】:

                          您可以使用此语法在 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;
                          }
                          ?>
                          

                          【讨论】:

                            【解决方案16】:

                            这里是 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);
                            

                            【讨论】:

                              【解决方案17】:

                              这对 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)
                              【解决方案18】:

                              我以这种方式获取枚举值:

                              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"
                              }
                              

                              【讨论】:

                              • 您的 SQL 缺少 TABLE_SCHEMA 的条件。很遗憾,我无法编辑您的答案。
                              【解决方案19】:

                              此线程中所有其他答案的问题在于,它们都没有正确解析枚举中字符串的所有特殊情况。

                              让我陷入循环的最大特例字符是单引号,因为它们本身被编码为 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 注入。

                              【讨论】:

                              • 很好的解决方案!当然,它不可能是 SQL 注入,因为我们是从我们自己的 DB 模式中获取值。
                              • 感谢您的方法。我在这样的数组中得到经常性值 {"building_regulations":"building_regulations","0":"building_regulations","list_of_owners":"list_of_owners","1":"list_of_owners"}。任何想法为什么? (在 phpmyadmin 中运行良好,但这是使用 POD 对象运行时的结果。)
                              • 有 3 种方法可以从 php 中的查询中从 mysql 行中提取值。 mysql_fetch_assoc 用正确的键拉入值,mysql_fetch_row 用数字键拉入值,而 mysql_fetch_array 可以将值作为一个或两个拉入。看起来您的 pdo 正在使用 mysql_fetch_array 进行此操作。应该有办法告诉它在获取期间不要这样做。
                              • 或者对您的 pdo 问题提供更简单的答案,只需运行 array_unique 或删除数字索引的 array_filter。
                              • 正如我已经在这篇文章的另一个答案中提到的,如果您有多个数据库,则必须指定 TABLE_SCHEMA。因此第一句必须是 SET @TableName='your_table_name', @ColName='your_col_name', @DBName='your_database_name';然后将 WHERE 子句扩展为 AND `TABLE_SCHEMA=@DBName,它甚至可以使用多个数据库。
                              【解决方案20】:

                              要获取可能值的列表已经有很好的记录,但是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 个字符的长度,删除了尾括号。

                              【讨论】:

                              • 如果您有多个数据库,您还必须指定 TABLE_SCHEMA。
                              【解决方案21】:

                              对于 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);
                              

                              【讨论】:

                                【解决方案22】:
                                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');
                                

                                【讨论】:

                                  【解决方案23】:

                                  奇怪的是,你们都没有想到,如果您使用枚举字段,这意味着要分配的值是“先验的”。

                                  因此,如果这些值是“先验”已知的,那么管理它们的最佳方法是通过一个非常简单的 Enum 类。

                                  Kiss 规则并保存一个数据库调用。

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

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

                                  【讨论】:

                                  • 问题说的是数据库中的值。这些值在 PHP 中是硬编码的。 (事实上​​,这里几乎每个答案都使用 PHP,这对我来说很奇怪,因为问题没有提到它。)
                                  【解决方案24】:
                                  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')

                                  【讨论】:

                                  • 这种类型的答案应该在评论中。
                                  • 栈溢出很聪明,因为信誉系统不让我评论。
                                  • 它必须是 LENGTH(COLUMN_TYPE) - 7。因此前导 ) 不在结果集中。
                                  【解决方案25】:

                                  这是自定义 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;
                                  
                                  }
                                  

                                  【讨论】:

                                    【解决方案26】:

                                    添加到 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()

                                    【讨论】:

                                      【解决方案27】:

                                      这将使用 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)));
                                      

                                      【讨论】:

                                        猜你喜欢
                                        • 2012-08-22
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 2019-10-02
                                        • 1970-01-01
                                        • 2010-12-05
                                        • 1970-01-01
                                        相关资源
                                        最近更新 更多