MySQL tamsayı alanı PHP'de dizge olarak döndürülür


127

MySQL veritabanında bir tablo alanım var:

userid INT(11)

Bu yüzden bu sorguyla sayfama çağırıyorum:

"SELECT userid FROM DB WHERE name='john'"

Sonra sonucu ele almak için yapıyorum:

$row=$result->fetch_assoc();

$id=$row['userid'];

Şimdi yaparsam:

echo gettype($id);

Bir ip alıyorum. Bunun bir tam sayı olması gerekmez mi?


2
MySQL sorgusu, satır türlerini veya diğer ilişkili bilgileri değil satır değerlerini verir. Her bir tablo hücresinde bulunan ham veriler. Bunu PHP'de hesaba
katmanız

Sütun türlerine ihtiyacınız varsa, buraya bakın forums.whirlpool.net.au/archive/526795
RichardTheKiwi

Okuyucular için seçilen cevap, sonuçların tekrarlanmasını içerir. Ancak daha iyi bir çözüm var. stackoverflow.com/a/1197424/5079380
Amr ElAdawy

1
@DanHanly - teknik olarak, MYSQL sorgusu (PHP'de) hücre değerinin bir dize gösterimini döndürür - veritabanında 32 bitlik bir tamsayı için depolanan gerçek hücre değeri ... 32 bitlik bir tamsayıdır, bir rakam dizisi değil .
ToolmakerSteve

benim için, kullandığımda $conn->query("your query")tamsayı alanlarını dize olarak aldım ama kullandığımda $conn->prepare("your query")parametreleri veritabanında oldukları gibi aldım
Bar Tzadok

Yanıtlar:


129

PHP kullanarak bir MySQL veritabanından veri seçtiğinizde, veri türü her zaman bir dizeye dönüştürülür. Aşağıdaki kodu kullanarak tekrar tam sayıya dönüştürebilirsiniz:

$id = (int) $row['userid'];

Veya işlevi kullanarak intval():

$id = intval($row['userid']);

79
MySQL'e Postgres arka planından geldiğimde, bunun baş belası olduğunu söyleme ihtiyacı duyuyorum. Postgres'te bir satırı getirdiğinizde, satır dizisindeki öğelerin uygun veri türlerine sahip olduğundan emin olursunuz. Şimdi her öğeyi beklediğim veri türüne manuel olarak dönüştürmek için kod yazmak zorundayım.
GordonM

25
Aynı şema ve veritabanı sunucusu üzerinde Laravel ve Mysql ile Windows üzerinde bazı testler yaptım. Windows'ta birincil anahtar bir Tamsayı olarak döndürülür ve Linux'ta bu bir Dize'dir.
AturSams

Tamam bu iyi bir fikir ama ya geri getirmen gereken binlerce alan varsa? Bu işlem biraz zaman alır .. Örneğimde, her gönderi için görüntülenme sayısını alırım, ardından tüm gönderilerimi bir tabloya yazdırırım, kullanıcıya Görünüm artan ve azalan olarak sıralama yapmasına izin veririm, ancak "1" ile "9 arasında sıralarım "veya" 9 "dan" 1 "e kadar ilk etapta" 9999 "," 91 "," 8111 "," 7 "vb. olabilir ...
KeizerBridge

@zehelvion hiç buna bir çözüm buldunuz mu?
Felipe Francisco

2
Döndürülen her alan bir dize VEYA NULL olacaktır .
Liam

73

Php için mysqlnd (yerel sürücü) kullanın.

Ubuntu'daysanız:

sudo apt-get install php5-mysqlnd
sudo service apache2 restart

Centos'taysanız:

sudo yum install php-mysqlnd
sudo service httpd restart

Yerel sürücü, tam sayı türlerini uygun şekilde döndürür.

Düzenle:

@Jeroen'in belirttiği gibi, bu yöntem yalnızca PDO için kullanıma hazırdır.
@LarsMoelleken'in belirttiği gibi, MYSQLI_OPT_INT_AND_FLOAT_NATIVE seçeneğini de true olarak ayarlarsanız, bu yöntem mysqli ile çalışacaktır.

Misal:

$mysqli = mysqli_init();
$mysqli->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, TRUE);

Bu duruma dair herhangi bir kanıt göremiyorum. Mysqlnd ve mysqli ile çalıştırıldığında, açıkça dize değerleri döndürülür.
Jeroen

@Jeroen emin misin? Mevcut birçok belge var. stackoverflow.com/questions/1197005/…
advait

Evet. Ayrıca aşağıdaki yorumlara da bakın. Bunu kendin test ettin mi? şimdi göründüğü gibi, mysqlnd bile yalnızca hazırlanmış ifadeler kullanırsanız uygun türleri döndürür. örnek: şunu $link = mysqli_connect('localhost', 'root', ''); mysqli_set_charset($link,'utf8'); $result = mysqli_query($link,'SELECT CAST(\'3.51\' AS DECIMAL(3,2))'); $row = mysqli_fetch_assoc($result); var_dump($row);döndürür: array(1) { ["CAST('3.51' AS DECIMAL(3,2))"]=> string(4) "3.51" }
Jeroen

1
Anladığım kadarıyla değil, PDO ve Mysqli ile eşit şekilde çalışmalı. Yukarıdaki yorumda gönderdiğiniz bağlantıda bile, OP'ye göre SADECE HAZIRLANMIŞ BİLDİRİMLERLE ÇALIŞTIĞI ve satır içi sorgularla çalışmadığı açıkça belirtilmiştir. o sayfadan alıntı: Ancak bu yalnızca PHP 5.3'tür (PHP 5.3 sürümünüzün mysqlnd ile derlenmiş olması koşuluyla (ve eski libmysql değil)) ve yalnızca hazırlanmış ifadeler için geçerli gibi görünüyor :-(
Jeroen

7
mysqli için "MYSQLI_OPT_INT_AND_FLOAT_NATIVE" seçeneğini de kullanabilirsiniz
Lars Moelleken

20

Bulduğum En Kolay Çözüm:

Json_encode'u sayılara benzeyen değerler için gerçek sayıları kullanmaya zorlayabilirsiniz:

json_encode($data, JSON_NUMERIC_CHECK) 

(PHP 5.3.3'ten beri).

Veya kimliğinizi bir int'e çevirebilirsiniz.

$row = $result->fetch_assoc();
$id = (int) $row['userid'];

1
Bir kullanma json_encodemümkünse int döküm dize çivi boğmak mikroskop kullanmak gibidir.
LibertyPaul

7
Bu, tüm posta kodlarını ve telefon numarasını bozacaktır. Uygulamanızda Hataları tanıtmanın iyi bir yolu. Çözüm, mysql sütun veri türüne saygı duymalı, değerden tahmin etmeye çalışmamalıdır.
Max Cuttins

1
Max Cuttins, puanınız geçerli. Ancak, DB'den beklenen tüm veri türlerini hesaba katabilirseniz, bu izlenecek mükemmel bir yoldur.
Ifedi Okonkwo

1
Bazen '06' gibi kimliklerin olduğunda bu sana zarar verir. Bu bayrak onu 6'ya dönüştürecektir. Bu yanlıştır çünkü bu kimlikler sıfırları takip etmelidir.
Hassan Dad Khan

Bu, UNIX_TIMESTAMP()örneğin tarafından yaratılan değerler için harika bir çözümdür .
David

18

$rsÇözümüm , sorgu sonucunu iletmek ve dönüş olarak dönüştürülen verilerin assoc dizisini almaktır:

function cast_query_results($rs) {
    $fields = mysqli_fetch_fields($rs);
    $data = array();
    $types = array();
    foreach($fields as $field) {
        switch($field->type) {
            case 3:
                $types[$field->name] = 'int';
                break;
            case 4:
                $types[$field->name] = 'float';
                break;
            default:
                $types[$field->name] = 'string';
                break;
        }
    }
    while($row=mysqli_fetch_assoc($rs)) array_push($data,$row);
    for($i=0;$i<count($data);$i++) {
        foreach($types as $name => $type) {
            settype($data[$i][$name], $type);
        }
    }
    return $data;
}

Örnek kullanım:

$dbconn = mysqli_connect('localhost','user','passwd','tablename');
$rs = mysqli_query($dbconn, "SELECT * FROM Matches");
$matches = cast_query_results($rs);
// $matches is now a assoc array of rows properly casted to ints/floats/strings

2
'NULL' dışında harika bir çözüm, settype () işlevi tarafından kullanılan bir değişken türüdür. Dolayısıyla, kodunuz, veritabanı tarafından döndürülen tüm NULL değerleri (gettype () == 'NULL' olan değerler) 'değeriyle' string 'türüne, 0 değeriyle' tamsayı 'türüne veya 0.0 değerli' float 'türüne değiştirir. İs_null ($ veri [$ i] [$ isim]) doğruysa settype'ı çağırmamalısınız.
Winter Dragoness

Beynin tekniğini seviyorum ama kodlama daha basit olabilir .
ToolmakerSteve

13

Hayır. Tablolarınızda tanımlanan veri türü ne olursa olsun, PHP'nin MySQL sürücüsü her zaman dizge olarak satır değerlerini sunar.

ID'nizi bir int'e çevirmeniz gerekiyor.

$row = $result->fetch_assoc();
$id = (int) $row['userid'];

6
Bu davranıştan sorumlu olan (doğrudan) PHP değil, veritabanı sürücüsüdür. PHP'den bir Postgres veritabanıyla arayüz oluşturuyorsanız, uygun veri türlerini geri alırsınız.
GordonM

5

Chad'in cevabını beğendim, özellikle sorgu sonuçları bir tarayıcıda javascript'e aktarılacağı zaman. Javascript, sayısal benzer varlıkları sayı olarak temiz bir şekilde ele alır, ancak dizeler olarak sayısal benzer varlıklarla uğraşmak için fazladan çalışma gerektirir. yani bunların üzerinde parseInt veya parseFloat kullanmalısınız.

Chad'in çözümünü temel alarak bunu kullanıyorum ve genellikle tam da ihtiyacım olan şeydir ve javascript ile kolay başa çıkmak için JSON kodlanabilen yapılar oluşturur.

while ($row = $result->fetch_assoc()) {
    // convert numeric looking things to numbers for javascript
    foreach ($row as &$val) {
        if (is_numeric($val))
            $val = $val + 0;
    }
}

0'a sayısal bir dizge eklemek, PHP'de sayısal bir tür üretir ve türü doğru bir şekilde tanımlar, böylece kayan noktalı sayılar tamsayılara bölünmez.


5

Bu , bağlantıda PDO::ATTR_EMULATE_PREPARESolarak ayarlandığında gerçekleşir true.

Yine de dikkatli olun false, parametrenin birden fazla kez kullanılmasına izin vermez. Geri dönen hata mesajlarının kalitesini de etkilediğine inanıyorum.


2

Bunu şununla yapabilirsiniz ...

  1. mysql_fetch_field ()
  2. mysqli_result :: fetch_field_direct veya
  3. PDOStatement :: getColumnMeta ()

... kullanmak istediğiniz uzantıya bağlı olarak. Birincisi, mysql uzantısı kullanımdan kaldırıldığı için önerilmez. Üçüncüsü hala deneyseldir.

Bu köprülerdeki yorumlar, türünüzü düz ve eski bir dizeden veritabanındaki orijinal türüne nasıl ayarlayacağınızı açıklamak için iyi bir iş çıkarır.

Bazı çerçeveler de bunu soyutlar (CodeIgniter sağlar $this->db->field_data()).

Ayrıca, elde edilen satırlarınız arasında döngü yapmak ve her biri için is_numeric () kullanmak gibi tahminler de yapabilirsiniz . Gibi bir şey:

foreach($result as &$row){
 foreach($row as &$value){
  if(is_numeric($value)){
   $value = (int) $value;
  }       
 }       
}

Bu, sayı gibi görünen her şeyi bire dönüştürür ... kesinlikle mükemmel değildir.


Şamandıralar için çalışmıyor. İs_numeric testini geçerler. Önce kayan değerleri test etmelisiniz.
Martin van Driel

@MartinvanDriel veya sadece sayı içeren ancak bir dizge olması gereken herhangi bir dize
treeface

@MartinvanDriel Eklemeyi deneyin:if (is_float()) { $value = (float)$value; }
adjwilli

2

Projemde genellikle birlikte alınan verileri "filtreleyen" harici bir işlev kullanıyorum mysql_fetch_assoc.

Tablonuzdaki alanları yeniden adlandırabilirsiniz, böylece hangi veri türünün depolandığını anlamak sezgiseldir.

Örneğin, her sayısal alana özel bir sonek ekleyebilirsiniz: eğer bir useridise INT(11)yeniden adlandırabilir userid_iveya bir ise UNSIGNED INT(11)yeniden adlandırabilirsiniz userid_u. Bu noktada, ilişkilendirilebilir diziyi girdi olarak alan (ile getirilen mysql_fetch_assoc) basit bir PHP işlevi yazabilir ve bu özel "anahtarlar" ile saklanan "değer" e çevrim uygulayabilirsiniz.


1

Hazırlanan ifadeler kullanılıyorsa, tür uygun olduğunda int olacaktır. Bu kod, her satırın ilişkilendirilebilir bir dizi olduğu bir satır dizisi döndürür. Eğer gibi fetch_assoc()ama korunmuş tip bilgi ile, tüm satırlar için çağrıldı.

function dbQuery($sql) {
    global $mysqli;

    $stmt = $mysqli->prepare($sql);
    $stmt->execute();
    $stmt->store_result();

    $meta = $stmt->result_metadata();
    $params = array();
    $row = array();

    while ($field = $meta->fetch_field()) {
      $params[] = &$row[$field->name];
    }

    call_user_func_array(array($stmt, 'bind_result'), $params);

    while ($stmt->fetch()) {
      $tmp = array();
      foreach ($row as $key => $val) {
        $tmp[$key] = $val;
      }
      $ret[] = $tmp;
    }

    $meta->free();
    $stmt->close();

    return $ret;
}

1

MySQL, diğer birçok dil için sürücülere sahiptir, verileri dizeye dönüştürmek verileri "standartlaştırır" ve kullanıcının int veya diğerlerine tip-cast değerleri vermesine bırakır.


1
İlkel türlerin hemen hemen bir "standart" olduğuna inanıyorum. Dile özgü bir sürücü bu dilin ihtiyaçlarını karşılayamazsa, bunun çok hayal kırıklığı yarattığını söyleyebilirim
Chung

1

Benim durumumda mysqlnd.souzantı kuruldu. AMA yapmadım pdo_mysqlnd.so. Yani sorun yerine pdo_mysql.soile değiştirilerek çözüldü pdo_mysqlnd.so.


0

Beynin tekniğini seviyorum ama kodlama daha basit olabilir:

function cast_query_results($result): array
{
    if ($result === false)
      return null;

    $data = array();
    $fields = $result->fetch_fields();
    while ($row = $result->fetch_assoc()) {
      foreach ($fields as $field) {
        $fieldName = $field->name;
        $fieldValue = $row[$fieldName];
        if (!is_null($fieldValue))
            switch ($field->type) {
              case 3:
                $row[$fieldName] = (int)$fieldValue;
                break;
              case 4:
                $row[$fieldName] = (float)$fieldValue;
                break;
              // Add other type conversions as desired.
              // Strings are already strings, so don't need to be touched.
            }
      }
      array_push($data, $row);
    }

    return $data;
}

Ayrıca bir sonuç kümesi yerine yanlış döndüren sorgu için kontrol ekledim.
Ve boş değeri olan bir alana sahip bir satırı kontrol etmek.
Ve eğer istenen tür bir dizeyse, bununla hiç vakit kaybetmem - zaten bir dizedir.


Bunu çoğu php kodunda kullanmakla uğraşmıyorum; Sadece php'nin otomatik tür dönüşümüne güveniyorum. Ancak çok fazla veriyi sorguluyorsanız, aritmetik hesaplamalar yapmak için önceden en uygun türlere çevirmek mantıklıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.