Açılır listelerimi bir DB'den olası değerleri otomatik olarak enum ile doldurmak istiyorum. MySQL'de bu mümkün mü?
Yanıtlar:
Sizin için kodlayıcı versiyonum var. Ayrıca değerleri değerlerden çıkarır.
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;
}
Değerleri şu şekilde sorgulayarak elde edebilirsiniz:
SELECT SUBSTRING(COLUMN_TYPE,5)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='databasename'
AND TABLE_NAME='tablename'
AND COLUMN_NAME='columnname'
Oradan onu bir diziye dönüştürmeniz gerekecek:
Bir ENUM sütunu için tüm olası değerleri belirlemek istiyorsanız, tbl_name LIKE enum_colDAN SÜTUNLARI GÖSTER'i kullanın ve çıktının Tür sütunundaki ENUM tanımını ayrıştırın.
Şunun gibi bir şey istersiniz:
$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]);
Bu size alıntılanan değerleri verecektir. MySQL her zaman bunları tek tırnak içinde döndürür. Değerdeki tek bir alıntı, tek bir alıntı ile kaçılır. Muhtemelen trim($val, "'")dizi elemanlarının her birini güvenle çağırabilirsiniz . Sen dönüştürmek isteyeceksiniz ''sadece içine '.
Aşağıdakiler $ trimmedvals dizi öğelerini tırnak işaretleri olmadan döndürecektir:
$trimmedvals = array();
foreach($vals as $key => $value) {
$value=trim($value, "'");
$trimmedvals[] = $value;
}
Bu yukarıdakilerin çoğuna benzer, ancak size döngüleri olmayan sonucu verir VE gerçekten istediğinizi alır: seçme seçenekleri oluşturmak için basit bir dizi.
BONUS: SET ve ENUM alan türlerinde çalışır.
$result = $db->query("SHOW COLUMNS FROM table LIKE 'column'");
if ($result) {
$option_array = explode("','",preg_replace("/(enum|set)\('(.+?)'\)/","\\2", $result[0]->Type));
}
$ option_array: Dizi ([0] => kırmızı [1] => yeşil [2] => mavi)
Dizeyi bir CSV (Virgülle Ayrılmış Değer) dizesi gibi ayrıştırabilirsiniz. PHP, bir CSV dizesini diziye dönüştüren str_getcsv adında harika bir yerleşik işleve sahiptir.
// 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);
Bu size aşağıdakine benzer bir şey vermelidir:
Array
(
[0] => blond
[1] => brunette
[2] => redhead
)
Bu yöntem aynı zamanda dizelerinizde tek tırnakların olmasına izin verir (iki tek tırnak kullanıldığına dikkat edin):
$enum_or_set = "'blond','brunette','red''head'";
Array
(
[0] => blond
[1] => brunette
[2] => red'head
)
Str_getcsv işlevi hakkında daha fazla bilgi için PHP kılavuzuna bakın: http://uk.php.net/manual/en/function.str-getcsv.php
str_getcsvsadece PHP 5> = 5.3.0'da çalışır, bu işlevselliği önceki sürümlerde almak istiyorsanız bu dosyayı ekleyebilirsiniz.
Bu, Chris Komlenic'in MySQL'in ENUM Veri Türünün Kötü Olmasının 8 Sebepinden biridir :
4. Farklı ENUM üyelerinin bir listesini elde etmek bir acıdır.
Çok yaygın bir ihtiyaç, bir seçim kutusu veya açılır listeyi veritabanından olası değerlerle doldurmaktır. Bunun gibi:
Renk seç:
[ select box ]Bu değerler 'renkler' adlı bir referans tablosunda saklanırsa, ihtiyacınız
SELECT * FROM colorsolan tek şey şudur: ... bu daha sonra açılır listeyi dinamik olarak oluşturmak için ayrıştırılabilir. Referans tablosundaki renkleri ekleyebilir veya değiştirebilirsiniz, seksi sipariş formlarınız otomatik olarak güncellenecektir. Harika.Şimdi kötü ENUM'u düşünün: Üye listesini nasıl çıkarırsınız? Tablonuzdaki ENUM sütununu DISTINCT değerleri için sorgulayabilirsiniz, ancak bu yalnızca gerçekte kullanılan ve tabloda mevcut olan değerleri döndürür , tüm olası değerleri olmayabilir. INFORMATION_SCHEMA'yı sorgulayabilir ve bunları bir komut dosyası diliyle sorgu sonucundan ayrıştırabilirsiniz, ancak bu gereksiz yere karmaşıktır. Aslında, ENUM sütununun üye listesini çıkarmanın zarif, tamamen SQL yolunu bilmiyorum.
Bunu yapmanın daha güncel bir yolu, bu benim için çalıştı:
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;
}
Nihayetinde, "enum ()" dan ayrıldığında enum değerleri yalnızca bir CSV dizesidir, bu nedenle onu bu şekilde ayrıştırın!
işte mysqli için
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);
İşte Patrick Savalle tarafından Laravel çerçevesi için uyarlanan aynı işlev
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 için bu işe yaradı:
$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);
Çıktı:
Array
(
[0] => Requested
[1] => Call Back
[2] => Busy
[3] => Not Reachable
[4] => Not Responding
)
Ben sadece jasonbar'ın şöyle bir sorgulama yaparken söylediği şeyi eklemek istiyorum:
SHOW columns FROM table
Sonucu bir dizi olarak çıkarırsanız, şöyle görünecektir:
array([0],[Field],[1],[Type],[2],[Null],[3],[Key],[4],[Default],[5],[Extra])
Burada [n] ve [metin] aynı değeri verir.
Bulduğum herhangi bir belgede gerçekten anlatılmamış. Orada başka ne olduğunu bilmek güzel.
$row = db_fetch_object($result);
if($row){
$type = $row->Type;
preg_match_all("/'([^']+)'/", $type, $matches,PREG_PATTERN_ORDER );
return $matches[1];
}
bunu dene
describe table columnname
size bu tablodaki sütunla ilgili tüm bilgileri verir;
Bazı modellerin yöntemi olarak Codeigniter uyarlama sürümü:
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];
}
Sonuç:
array(2) {
[0]=> string(13) "administrator"
[1]=> string(8) "customer"
}
Hepiniz bazı garip ve karmaşık normal ifade kalıpları kullanıyorsunuz x)
İşte preg_match içermeyen çözümüm:
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'de olası değerleri enum almak için bu sözdizimini kullanabilirsiniz:
$syntax = "SELECT COLUMN_TYPY FROM information_schema.`COLUMNS`
WHERE TABLE_NAME = '{$THE_TABLE_NAME}'
AND COLUMN_NAME = '{$THE_COLUMN_OF_TABLE}'";
ve değer elde edersiniz, örnek: enum ('Erkek', 'Kadın')
bu örnek 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;
}
?>
Bu ileti dizisindeki diğer her yanıtla ilgili sorun, hiçbirinin enum içindeki dizelerin tüm özel durumlarını düzgün bir şekilde ayrıştırmamasıdır.
Beni bir döngüye sokan en büyük özel durum karakteri, kendilerini 2 tek tırnak olarak kodladıkları için tek tırnaklardı! Bu nedenle, örneğin, değere sahip bir enum 'a'olarak kodlanır enum('''a'''). Korkunç, değil mi?
Çözüm, verileri sizin için ayrıştırmak için MySQL kullanmaktır!
Bu iş parçacığında diğer herkes PHP kullandığından, ben bunu kullanacağım. Tam kod aşağıdadır. Sonra açıklayacağım. Parametre $FullEnumString, diğer tüm yanıtlardan kullanmak istediğiniz yöntemden çıkarılan tüm enum dizesini tutacaktır. RunQuery()ve FetchRow()(ilişkisel olmayan) favori DB erişim yöntemlerinizin standlarıdır.
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 değerinin beklediğimizle eşleştiğini onaylar, yani "enum(".$STUFF.")"(öncesinde veya sonrasında hiçbir şey olmadan). Preg_match başarısız olursa NULLdöndürülür.
Bu preg_matchaynı zamanda tuhaf SQL sözdiziminde kaçan dizelerin listesini de $Matches[1]. Şimdi, bundan gerçek verileri elde edebilmek istiyoruz. Yani koşuyorsunuz "SELECT ".$Matches[1]ve ilk kaydınızdaki dizelerin tam listesi var!
Yani o kaydı a ile çıkarın FetchRow(RunQuery(...))ve bitirdiniz.
Tüm bunları SQL'de yapmak istiyorsanız, aşağıdakileri kullanabilirsiniz
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;
Not: Herhangi birinin bu konuda bir şey söylemesini engellemek için, hayır, bu yöntemin SQL enjeksiyonuna yol açabileceğine inanmıyorum.
Olası değerlerin listesini almak için iyi bir şekilde belgelenmiştir, ancak değerleri parantez içinde döndüren başka bir yanıtı genişleterek, onları virgülle ayrılmış bir liste bırakarak çıkarıp daha sonra patlatma türü bir işlevi kullanmama izin vermek istedim bir dizi almak için gerekli.
SELECT
SUBSTRING(COLUMN_TYPE, 6, LENGTH(COLUMN_TYPE) - 6) AS val
FROM
information_schema.COLUMNS
WHERE
TABLE_NAME = 'articles'
AND
COLUMN_NAME = 'status'
SUBSTRINGŞimdi 6 karakter başlar ve arka parantez çıkarılması, toplam en az 6 karakter daha kısa olan bir uzunluğa kullanır.
PHP 5.6+ için
$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);
Bir enum alanı kullanıyorsanız, bunun atanacak değerlerin "a priori" olduğu anlamına geldiğini hiçbirinizin düşünmemesi olağanüstü.
Bu nedenle, değerler "a priori" olarak biliniyorsa, onları yönetmenin en iyi yolu çok basit bir Enum sınıfı kullanmaktır.
Kuralı öpün ve bir veritabanı çağrısını kaydedin.
<?php
class Genre extends \SplEnum {
const male = "Male";
const female = "Female";
}
Enum değerlerini şu şekilde alıyorum:
SELECT COLUMN_TYPE
FROM information_schema.`COLUMNS`
WHERE TABLE_NAME = 'tableName'
AND COLUMN_NAME = 'columnName';
Bu sql'yi çalıştırıyorum: enum ('BDBL', 'AB Bank')
sonra aşağıdaki kodu kullanarak sadece değeri filtreledim:
preg_match("/^enum\(\'(.*)\'\)$/", $type, $matches);
$enum = explode("','", $matches[1]);
var_dump($enum) ;
Çıktı :
array (2) {[0] => string (4) "BDBL" [1] => string (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 ;
Misal:
SELECT ENUM_VALUES('table_name', 'col_name');
VAL FROM information_schema.COLUMNS WHERE TABLE_NAME = 'makaleler' AND COLUMN_NAME = 'durum' olarak SUBSTRING (COLUMN_TYPE, 6, LENGTH (COLUMN_TYPE) - 6) SEÇİN
Enum için çalışmaz ('', 'X''XX')
İşte özel bir WordPress tablosu için bir çözüm. Bu bir virgül olmadan ENUM değerleri için çalışacak (,)onlarda
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;
}