Como posso obter valores possíveis de enum em um banco de dados MySQL?


96

Desejo preencher meus menus suspensos com valores possíveis de enum de um banco de dados automaticamente. Isso é possível no MySQL?

Respostas:


97

Eu tenho uma versão codeigniter para você. Ele também remove as aspas dos valores.

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
Essa solução será interrompida se os próprios valores enum contiverem vírgulas.
Fo.


3
Versão do PHP: $ type = $ this-> mysql-> select ("MOSTRAR COLUNAS DE $ table WHERE Field = '$ field'") [0] ["Type"];
Alessandro.Vegna

para converter o valor do tipo em um array usando php eu fiz assim: $ segmentos = str_replace ("'", "", $ row [0] [' Type ']); $ segmentos = str_replace ("enum", "", $ segmentos); $ segmentos = str_replace ("(", "", $ segmentos); $ segmentos = str_replace (")", "", $ segmentos); $ segmentList = explode (',', $ segmentos);
Gustavo Emmel

1
Eu adicionei uma resposta com uma forma de prova completa para extrair todos os valores enum, não importa os caracteres dentro deles.
Dakusan

53

Você pode obter os valores consultando-os assim:

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

A partir daí, você precisará convertê-lo em uma matriz:

  • avalie isso diretamente em um array se você for preguiçoso (embora o escape de aspas simples do MySQL possa ser incompatível), ou
  • $ options_array = str_getcsv ($ options, ',', "'") possivelmente funcionaria (se você alterar a substring para pular os parênteses de abertura e fechamento), ou
  • uma expressão regular

31

Referência MySQL

Se você deseja determinar todos os valores possíveis para uma coluna ENUM, use SHOW COLUMNS FROM nome_tabela LIKE enum_col e analise a definição ENUM na coluna Tipo da saída.

Você gostaria de algo como:

$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]);

Isso lhe dará os valores cotados. O MySQL sempre os retorna entre aspas simples. Uma aspa simples no valor é escapada por uma aspa simples. Você provavelmente pode chamar com segurança trim($val, "'")cada um dos elementos da matriz. Você vai querer se converter ''em justo '.

O seguinte retornará itens da matriz $ trimmedvals sem aspas:

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

11

Isso é parecido com muitos dos itens acima, mas fornece o resultado sem loops, E dá o que você realmente deseja: um array simples para gerar opções de seleção.

BÔNUS: funciona para os tipos de campo SET e 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] => vermelho [1] => verde [2] => azul)


10

Esta é uma das 8 razões de Chris Komlenic pelas quais o tipo de dados ENUM do MySQL é mau :

 4. Conseguir uma lista de membros distintos do ENUM é uma dor.

Uma necessidade muito comum é preencher uma caixa de seleção ou lista suspensa com valores possíveis do banco de dados. Como isso:

Selecione a cor:

[ select box ]

Se esses valores forem armazenados em uma tabela de referência chamada 'cores', tudo que você precisa é: SELECT * FROM colors... que pode então ser analisado para gerar dinamicamente a lista suspensa. Você pode adicionar ou alterar as cores na tabela de referência e seus formulários de pedido sexy serão atualizados automaticamente. Impressionante.

Agora considere o mal ENUM: como você extrai a lista de membros? Você pode consultar a coluna ENUM em sua tabela para obter os valores DISTINCT, mas isso só retornará os valores que são realmente usados ​​e presentes na tabela , não necessariamente todos os valores possíveis. Você pode consultar INFORMATION_SCHEMA e analisá-los fora do resultado da consulta com uma linguagem de script, mas isso é desnecessariamente complicado. Na verdade, não conheço nenhuma maneira elegante e puramente SQL de extrair a lista de membros de uma coluna ENUM.


9

Você pode analisar a string como se fosse uma string CSV (Comma Separated Value). O PHP tem uma ótima função integrada chamada str_getcsv que converte uma string CSV em um array.

// 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);

Isso deve dar a você algo semelhante ao seguinte:

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

Este método também permite que você coloque aspas simples em suas strings (observe o uso de duas aspas simples):

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

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

Para obter mais informações sobre a função str_getcsv, verifique o manual do PHP: http://uk.php.net/manual/en/function.str-getcsv.php


1
O exemplo que dei não mostra como obter as informações de campo do banco de dados, mas há muitos exemplos nesta página para mostrar como fazer isso.
bashaus

2
str_getcsvsó funciona no PHP 5> = 5.3.0, você pode incluir este arquivo se quiser obter esta funcionalidade em versões anteriores.
Steve

1
Essa deve ser a maneira correta de lidar com isso, pois considera aspas e vírgulas de escape dentro das strings.
Kristoffer Sall-Storgaard

1
Solução brilhante, economiza tempo;)
John

6

Uma maneira mais atualizada de fazer isso funcionou para mim:

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

Em última análise, os valores enum quando separados de "enum ()" são apenas uma string CSV, então analise-a como tal!


5

aqui é para 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

Aqui está a mesma função dada por Patrick Savalle adaptada para o framework 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;

}

2

Eu simplesmente quero acrescentar o que jasonbar diz, ao fazer consultas como:

SHOW columns FROM table

Se você obtiver o resultado como uma matriz, será semelhante a este:

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

Onde [n] e [texto] fornecem o mesmo valor.
Realmente não disse em qualquer documentação que encontrei. É simplesmente bom saber o que mais existe.


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


}

2

tente isso

describe table columnname

dá a você todas as informações sobre aquela coluna na tabela;


2

Codeigniter adaptando a versão como método de algum modelo:

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];
}

Resultado:

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

Isso não fornece uma resposta para a pergunta. Para criticar ou solicitar esclarecimentos de um autor, deixe um comentário abaixo de sua postagem - você sempre pode comentar suas próprias postagens e, assim que tiver reputação suficiente , poderá comentar em qualquer postagem .
worldofjr

Você tem certeza? Por quê? O resultado desta função pode ser inserido simplesmente em uma função como form_dropdown ...
Андрій Глущенко

2

Todos vocês usam alguns padrões regex estranhos e complexos x)

Aqui está minha solução sem 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

Você pode usar esta sintaxe para obter os valores possíveis de enum no MySQL QUERY:

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

e você obtém um valor, por exemplo: enum ('Masculino', 'Feminino')

este é um exemplo de 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

Para o Laravel isso funcionou:

$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);

Resultado:

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

2

O problema com todas as outras respostas neste encadeamento é que nenhuma delas analisa adequadamente todos os casos especiais das strings dentro do enum.

O maior caractere de caso especial que estava me deixando confuso eram aspas simples, já que eles são codificados como 2 aspas simples juntas! Portanto, por exemplo, um enum com o valor 'a'é codificado como enum('''a'''). Horrível, certo?

Bem, a solução é usar o MySQL para analisar os dados para você!

Já que todo mundo está usando PHP neste tópico, é isso que usarei. A seguir está o código completo. Vou explicar depois. O parâmetro $FullEnumStringconterá toda a string enum, extraída de qualquer método que você deseja usar de todas as outras respostas. RunQuery()e FetchRow()(não associativo) são substitutos para seus métodos de acesso de banco de dados favoritos.

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

preg_match('/^enum\((.*)\)$/iD', $FullEnumString, $Matches)confirma que o valor enum corresponde ao que esperamos, ou seja, "enum(".$STUFF.")"(sem nada antes ou depois). Se o preg_match falhar, NULLé retornado.

Isso preg_matchtambém armazena a lista de strings, escapadas na estranha sintaxe SQL, em $Matches[1]. Em seguida, queremos ser capazes de obter os dados reais disso. Então, você apenas executa "SELECT ".$Matches[1]e tem uma lista completa das cordas em seu primeiro registro!

Então, basta puxar aquele registro com um FetchRow(RunQuery(...))e pronto.

Se você quiser fazer tudo isso em SQL, poderá usar o seguinte

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 Para evitar que alguém diga algo sobre isso, não, não acredito que esse método possa levar à injeção de SQL.


Ótima solução! Claro, não poderia ser a injeção de SQL, porque estamos pegando valores de nosso próprio esquema de banco de dados.
terales

Obrigado pela abordagem. Estou obtendo valores recorrentes na matriz como este {"building_regulations": "building_regulations", "0": "building_regulations", "list_of_owners": "list_of_owners", "1": "list_of_owners"}. Alguma ideia por quê? (Funciona bem no phpmyadmin, mas este é o resultado quando executado usando um objeto POD.)
Guney Ozsan

Existem 3 maneiras de obter valores de uma linha do mysql de uma consulta em php. mysql_fetch_assoc extrai os valores com as chaves apropriadas, mysql_fetch_row extrai os valores com chaves numéricas e mysql_fetch_array pode extrair os valores como um ou ambos. Parece que seu pdo está usando mysql_fetch_array para esta operação. Deve haver uma maneira de dizer a ele para não fazer isso durante a busca.
Dakusan de

Ou uma resposta muito mais simples para seu problema de PDO, basta executar um array_unique ou um array_filter que remove os índices numéricos.
Dakusan

Excelente! É assim que você faz o MySQL fazer todo o trabalho duro.
Spencer Williams

2

Buscar a lista de valores possíveis foi bem documentado, mas expandindo em outra resposta que retornou os valores entre parênteses , eu queria retirá-los, deixando-me com uma lista separada por vírgulas que me permitiria usar uma função do tipo explodir sempre que eu necessário para obter uma matriz.

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

O SUBSTRINGnow começa no 6º caractere e usa um comprimento que é 6 caracteres mais curto que o total, removendo o parêntese final.


1

isso vai funcionar para mim:

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__'

e depois

explode(',', $data)

1

Para 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

É extraordinário como nenhum de vocês pensou que se você estiver usando um campo enum, isso significa que os valores a serem atribuídos são conhecidos "a priori".

Portanto, se os valores são conhecidos "a priori", a melhor maneira de gerenciá-los é por meio de uma classe Enum muito simples.

Beije a regra e salve uma chamada de banco de dados.

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

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


0

Eu obtenho valores enum desta forma:

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

Executando este sql, obtive: enum ('BDBL', 'Banco AB')

então, filtrou apenas o valor usando o seguinte código:

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

Resultado :

matriz (2) {[0] => string (4) "BDBL" [1] => string (7) "Banco AB"}


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 ;

Exemplo:

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

0

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

Não funcionaria para enum ('', 'X''XX')


1
Este tipo de resposta deve ser um comentário.
Rahul harinkhede

o estouro de pilha é bastante inteligente e não me permite comentar por causa do sistema de reputação.
Salvor Hardin
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.