ฟิลด์จำนวนเต็ม MySQL จะถูกส่งกลับเป็นสตริงใน PHP


127

ฉันมีช่องตารางในฐานข้อมูล MySQL:

userid INT(11)

ดังนั้นฉันจึงเรียกมันไปที่เพจของฉันด้วยข้อความค้นหานี้:

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

จากนั้นสำหรับการจัดการผลลัพธ์ฉันทำ:

$row=$result->fetch_assoc();

$id=$row['userid'];

ตอนนี้ถ้าฉันทำ:

echo gettype($id);

ฉันได้รับสตริง นี่ควรเป็นจำนวนเต็มไม่ใช่หรือ


2
แบบสอบถาม MySQL ให้ค่าแถวไม่ใช่ประเภทแถวหรือข้อมูลที่เกี่ยวข้องอื่น ๆ เพียงข้อมูลดิบที่อยู่ในเซลล์ตารางแต่ละเซลล์ คุณจะต้องพิจารณาใน PHP
Dan Hanly

หากคุณต้องการประเภทคอลัมน์โปรดดูที่นี่forums.whirlpool.net.au/archive/526795
RichardTheKiwi

สำหรับผู้อ่านคำตอบที่เลือกเกี่ยวข้องกับการวนซ้ำผลลัพธ์ แต่มีทางออกที่ดีกว่า. stackoverflow.com/a/1197424/5079380
Amr ElAdawy

1
@DanHanly - ในทางเทคนิคคิวรี MYSQL (ใน PHP) จะส่งกลับการแสดงสตริงของค่าเซลล์ - ค่าเซลล์จริงที่เก็บไว้ในฐานข้อมูลสำหรับจำนวนเต็ม 32 บิตคือ ... จำนวนเต็ม 32 บิตไม่ใช่สตริงของตัวเลข .
ToolmakerSteve

สำหรับฉันเมื่อฉันใช้$conn->query("your query")ฉันได้ฟิลด์จำนวนเต็มเป็นสตริง แต่เมื่อฉันใช้$conn->prepare("your query")ฉันได้รับพารามิเตอร์ตามที่อยู่ในฐานข้อมูล
Bar Tzadok

คำตอบ:


129

เมื่อคุณเลือกข้อมูลจากฐานข้อมูล MySQL โดยใช้ PHP ประเภทข้อมูลจะถูกแปลงเป็นสตริงเสมอ คุณสามารถแปลงกลับเป็นจำนวนเต็มโดยใช้รหัสต่อไปนี้:

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

หรือโดยใช้ฟังก์ชันintval():

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

80
เมื่อมาที่ MySQL จากภูมิหลังของ Postgres ฉันรู้สึกว่าจำเป็นต้องบอกว่านี่เป็นความเจ็บปวดอย่างมากในตูด เมื่อคุณดึงข้อมูลแถวใน Postgres คุณ coudl ต้องแน่ใจว่าองค์ประกอบในอาร์เรย์แถวมีชนิดข้อมูลที่เหมาะสม ตอนนี้ฉันต้องเขียนโค้ดเพื่อแคสต์ทุกองค์ประกอบด้วยตนเองไปยังประเภทข้อมูลที่ฉันคาดหวัง
GordonM

25
ฉันเพิ่งทำการทดสอบบางอย่างบน Windows ด้วย Laravel และ Mysql บนสคีมาและเซิร์ฟเวอร์ฐานข้อมูลเดียวกัน ใน Windows คีย์หลักจะถูกส่งกลับเป็นจำนวนเต็มและบน Linux เป็น String
AturSams

โอเคเป็นความคิดที่ดี แต่ถ้าคุณมีหลายพันฟิลด์ที่จะดึง? ขั้นตอนนี้ใช้เวลาสักครู่ .. ในตัวอย่างของฉันฉันเรียกดูจำนวนการดูสำหรับแต่ละโพสต์จากนั้นฉันก็พิมพ์โพสต์ทั้งหมดของฉันในตารางฉันอนุญาตให้ผู้ใช้จัดเรียงตาม View asc และ desc แต่จะเรียงลำดับตาม "1" ถึง "9 "หรือ" 9 "ถึง" 1 "ดังนั้นในตอนแรกคุณอาจมี" 9999 "" 91 "" 8111 "" 7 "ฯลฯ ...
KeizerBridge

2
ทุกสาขาส่งกลับจะเป็นสตริงหรือโมฆะ
Liam

1
เหตุใดฉันจึงได้รับค่า int สำหรับคอลัมน์ int (ฉันใช้คำสั่งที่เตรียมไว้และทดสอบบน windows) !
นักบัญชีم

73

ใช้ mysqlnd (ไดรเวอร์ดั้งเดิม) สำหรับ php

หากคุณใช้ Ubuntu:

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

หากคุณใช้ Centos:

sudo yum install php-mysqlnd
sudo service httpd restart

ไดรเวอร์ดั้งเดิมส่งคืนชนิดจำนวนเต็มอย่างเหมาะสม

แก้ไข:

ดังที่ @Jeroen ได้ชี้ให้เห็นวิธีนี้จะใช้ได้เฉพาะกับ PDO เท่านั้น
ดังที่ @LarsMoelleken ได้ระบุไว้วิธีนี้จะใช้ได้กับ mysqli หากคุณตั้งค่าตัวเลือก MYSQLI_OPT_INT_AND_FLOAT_NATIVE เป็น true

ตัวอย่าง:

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

ฉันไม่เห็นหลักฐานใด ๆ เกี่ยวกับ stament นี้ รันด้วย mysqlnd และ mysqli จะส่งคืนค่าสตริงอย่างชัดเจน
Jeroen

@ เจโรนแน่ใจเหรอ มีเอกสารมากมาย stackoverflow.com/questions/1197005/…
advait

ใช่. ดูความคิดเห็นด้านล่างด้วย คุณทดสอบด้วยตัวเองหรือไม่? ตามที่ปรากฏในตอนนี้แม้แต่ mysqlnd จะส่งคืนเฉพาะประเภทที่เหมาะสมหากคุณใช้คำสั่งที่เตรียมไว้ ตัวอย่าง: $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);ผลตอบแทน: array(1) { ["CAST('3.51' AS DECIMAL(3,2))"]=> string(4) "3.51" }
Jeroen

1
ไม่ใช่ว่าฉันเข้าใจมันควรจะทำงานกับ PDO และ Mysqli ได้อย่างเท่าเทียมกัน แม้ในลิงก์ที่คุณโพสต์ไว้ด้านบนในความคิดเห็นก็มีการระบุไว้อย่างชัดเจนว่าใช้ได้กับข้อความที่เตรียมไว้เท่านั้นและไม่ใช่การสอบถามแบบอินไลน์ตาม OP คำพูดจากหน้านั้น: แต่นี่เป็น PHP 5.3 เท่านั้น (หาก PHP 5.3 เวอร์ชันของคุณรวบรวมด้วย mysqlnd (ไม่ใช่ libmysql เก่า)) และดูเหมือนว่าจะเป็นกรณีสำหรับคำสั่งที่เตรียมไว้เท่านั้น :-(
Jeroen

7
คุณยังสามารถใช้ "MYSQLI_OPT_INT_AND_FLOAT_NATIVE" สำหรับ mysqli
Lars Moelleken

20

ทางออกที่ง่ายที่สุดที่ฉันพบ:

คุณสามารถบังคับให้ json_encode ใช้ตัวเลขจริงสำหรับค่าที่ดูเหมือนตัวเลข:

json_encode($data, JSON_NUMERIC_CHECK) 

(ตั้งแต่ PHP 5.3.3)

หรือคุณสามารถแคสต์ ID ของคุณเป็น int

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

1
การใช้json_encodeสายอักขระเพื่อโยนเป็น int ถ้าเป็นไปได้ก็เหมือนกับการใช้กล้องจุลทรรศน์เพื่อทำให้เล็บขบ
LibertyPaul

7
การดำเนินการนี้จะทำลายรหัสไปรษณีย์และหมายเลขโทรศัพท์ทั้งหมด วิธีที่ดีในการแนะนำ Bugs ในแอพของคุณ วิธีแก้ปัญหาต้องเป็นไปตามประเภทข้อมูลคอลัมน์ mysql อย่าพยายามเดาจากค่า
Max Cuttins

1
Max Cuttins คะแนนของคุณถูกต้อง อย่างไรก็ตามหากคุณสามารถระบุประเภทข้อมูลทั้งหมดที่คาดหวังจากฐานข้อมูลได้นี่จะเป็นเส้นทางที่สมบูรณ์แบบ
Ifedi Okonkwo

1
สิ่งนี้จะทำร้ายคุณเมื่อบางครั้งคุณมีรหัสบางอย่างเช่น '06' แฟล็กนี้จะแปลงเป็น 6 ซึ่งไม่ถูกต้องเนื่องจากรหัสเหล่านั้นควรเก็บค่าศูนย์ต่อท้าย
Hassan Dad Khan

นี่เป็นวิธีแก้ปัญหาที่ยอดเยี่ยมสำหรับค่าที่สร้างขึ้นUNIX_TIMESTAMP()เช่น
เดวิด

18

วิธีแก้ปัญหาของฉันคือการส่งผลการค้นหา$rsและรับอาร์เรย์ Assoc ของข้อมูลที่ร่ายเป็นผลตอบแทน:

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

ตัวอย่างการใช้งาน:

$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' ยังเป็นประเภทตัวแปรที่ใช้โดยฟังก์ชัน settype () ดังนั้นโค้ดของคุณจึงเปลี่ยนค่า NULL ทั้งหมดที่ฐานข้อมูลส่งคืน (ค่าที่ gettype () == 'NULL') เป็น 'string' type ด้วย '' value, 'integer' type with 0 value หรือ 'float' type with 0.0 value คุณไม่จำเป็นต้องเรียก settype ถ้า is_null ($ data [$ i] [$ name]) เป็นจริง
Winter Dragoness

ฉันชอบเทคนิคของผู้บงการ แต่การเข้ารหัสอาจง่ายกว่านี้
ToolmakerSteve

13

ไม่คำนึงถึงประเภทข้อมูลที่กำหนดไว้ในตารางของคุณไดรเวอร์ MySQL ของ PHP จะให้บริการค่าแถวเป็นสตริงเสมอ

คุณต้องแคสต์ ID ของคุณเป็น int

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

6
ไม่ใช่ PHP ที่รับผิดชอบ (โดยตรง) สำหรับพฤติกรรมนี้ แต่เป็นไดรเวอร์ฐานข้อมูล หากคุณกำลังเชื่อมต่อกับฐานข้อมูล Postgres จาก PHP คุณจะได้รับประเภทข้อมูลที่เหมาะสมกลับคืนมา
GordonM

5

ฉันชอบคำตอบของชาดโดยเฉพาะอย่างยิ่งเมื่อผลการค้นหาจะถูกส่งต่อไปยังจาวาสคริปต์ในเบราว์เซอร์ Javascript จะจัดการกับเอนทิตีที่เป็นตัวเลขเป็นตัวเลขได้อย่างหมดจด แต่ต้องใช้งานเพิ่มเติมเพื่อจัดการกับเอนทิตีที่เป็นตัวเลขเป็นสตริง คือต้องใช้ parseInt หรือ parseFloat กับพวกเขา

การสร้างโซลูชันของ Chad ฉันใช้สิ่งนี้และมักเป็นสิ่งที่ฉันต้องการและสร้างโครงสร้างที่สามารถเข้ารหัส JSON เพื่อให้จัดการกับจาวาสคริปต์ได้ง่าย

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 จะสร้างประเภทตัวเลขใน PHP และระบุประเภทอย่างถูกต้องดังนั้นตัวเลขทศนิยมจะไม่ถูกตัดทอนเป็นจำนวนเต็ม


5

สิ่งนี้จะเกิดขึ้นเมื่อPDO::ATTR_EMULATE_PREPARESตั้งค่าเป็นtrueบนการเชื่อมต่อ

ระวังด้วยการตั้งค่าให้falseไม่อนุญาตให้ใช้พารามิเตอร์มากกว่าหนึ่งครั้ง ฉันเชื่อว่ามันส่งผลต่อคุณภาพของข้อความแสดงข้อผิดพลาดที่กลับมาด้วย


2

คุณสามารถทำได้ด้วย ...

  1. mysql_fetch_field ()
  2. mysqli_result :: fetch_field_directหรือ
  3. PDOStatement :: getColumnMeta ()

... ขึ้นอยู่กับนามสกุลที่คุณต้องการใช้ ไม่แนะนำให้ใช้ตัวแรกเนื่องจากส่วนขยาย mysql เลิกใช้งานแล้ว อย่างที่สามยังอยู่ระหว่างการทดลอง

ความคิดเห็นในการเชื่อมโยงหลายมิติเหล่านี้ช่วยอธิบายวิธีการตั้งค่าประเภทของคุณจากสตริงเก่าธรรมดาไปเป็นประเภทดั้งเดิมในฐานข้อมูล

กรอบงานบางส่วนยังเป็นนามธรรม (CodeIgniter ให้$this->db->field_data())

คุณยังสามารถเดาได้เช่นการวนซ้ำแถวผลลัพธ์และใช้is_numeric ()ในแต่ละแถว สิ่งที่ต้องการ:

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

สิ่งนี้จะเปลี่ยนอะไรก็ได้ที่ดูเหมือนตัวเลขเป็นหนึ่ง ... ไม่สมบูรณ์แบบแน่นอน


ใช้ไม่ได้กับการลอย พวกเขาผ่านการทดสอบ is_numeric คุณควรทดสอบการลอยตัวก่อน
Martin van Driel

@MartinvanDriel หรือสตริงใด ๆ ที่มีเฉพาะตัวเลข แต่ควรเป็นสตริง
treeface

@MartinvanDriel ลองเพิ่ม:if (is_float()) { $value = (float)$value; }
adjwilli

2

ในโครงการของฉันฉันมักจะใช้ฟังก์ชั่นภายนอกที่ "ฟิลเตอร์" mysql_fetch_assocดึงข้อมูลด้วย

คุณสามารถเปลี่ยนชื่อเขตข้อมูลในตารางของคุณเพื่อให้เข้าใจได้ง่ายว่าจะจัดเก็บข้อมูลประเภทใด

ตัวอย่างเช่นคุณสามารถเพิ่มคำต่อท้ายพิเศษลงในช่องตัวเลขแต่ละช่อง: ถ้าuseridเป็นINT(11)คุณสามารถเปลี่ยนชื่อได้userid_iหรือถ้าเป็นUNSIGNED INT(11)คุณสามารถเปลี่ยนชื่อuserid_uได้ ณ จุดนี้คุณสามารถเขียนฟังก์ชัน PHP ง่ายๆที่รับเป็นอินพุตของอาร์เรย์ที่เชื่อมโยง (ดึงมาด้วยmysql_fetch_assoc) และใช้การแคสต์กับ "ค่า" ที่จัดเก็บด้วย "คีย์" พิเศษเหล่านั้น


1

หากมีการใช้คำสั่งที่เตรียมไว้ประเภทจะเป็น int ตามความเหมาะสม โค้ดนี้ส่งคืนอาร์เรย์ของแถวโดยแต่ละแถวเป็นอาร์เรย์ที่เชื่อมโยงกัน เหมือนกับว่าfetch_assoc()ถูกเรียกสำหรับทุกแถว แต่มีข้อมูลประเภทที่เก็บรักษาไว้

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 มีไดรเวอร์สำหรับภาษาอื่น ๆ อีกมากมายการแปลงข้อมูลเป็นสตริงข้อมูล "standardizes" และปล่อยให้ผู้ใช้พิมพ์ค่า cast เป็น int หรืออื่น ๆ


1
ฉันเชื่อว่าประเภทดั้งเดิมค่อนข้างเป็น "มาตรฐาน"? หากไดรเวอร์เฉพาะภาษาไม่สามารถตอบสนองความต้องการของภาษานั้นได้ฉันจะบอกว่ามันน่าผิดหวังมาก
Chung

1

ในกรณีของฉันmysqlnd.soมีการติดตั้งส่วนขยาย pdo_mysqlnd.soแต่ฉันไม่ได้ ดังนั้นปัญหาจึงได้รับการแก้ไขโดยการแทนที่pdo_mysql.soด้วยpdo_mysqlnd.so.


0

ฉันชอบเทคนิคของผู้บงการแต่การเข้ารหัสอาจง่ายกว่านี้:

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

ฉันยังเพิ่มการตรวจสอบการสืบค้นกลับเป็นเท็จแทนที่จะเป็นชุดผลลัพธ์
และตรวจสอบแถวที่มีเขตข้อมูลที่มีค่า null
และถ้าประเภทที่ต้องการเป็นสตริงฉันจะไม่เสียเวลากับมันเลย - มันเป็นสตริงอยู่แล้ว


ฉันไม่ต้องกังวลกับการใช้สิ่งนี้ในโค้ด php ส่วนใหญ่ ฉันพึ่งการแปลงประเภทอัตโนมัติของ php แต่ถ้าค้นหาข้อมูลจำนวนมากเพื่อทำการคำนวณทางคณิตศาสตร์ก็เหมาะสมที่จะส่งไปยังประเภทที่เหมาะสมที่สุดไว้ข้างหน้า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.