Trường số nguyên MySQL được trả về dưới dạng chuỗi trong PHP


127

Tôi có một trường bảng trong cơ sở dữ liệu MySQL:

userid INT(11)

Vì vậy, tôi đang gọi nó đến trang của tôi với truy vấn này:

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

Sau đó để xử lý kết quả tôi làm:

$row=$result->fetch_assoc();

$id=$row['userid'];

Bây giờ nếu tôi làm:

echo gettype($id);

Tôi nhận được một chuỗi. Đây không phải là một số nguyên?


2
truy vấn MySQL cung cấp các giá trị hàng không phải là loại hàng hoặc bất kỳ thông tin liên quan nào khác. Chỉ là dữ liệu thô trong mỗi ô của bảng. Bạn sẽ phải tính đến điều này trong PHP
Dan Hanly

Nếu bạn cần các loại cột, xem tại đây forums.whirlpool.net.au/archive/526795
RichardTheKiwi

Đối với độc giả, câu trả lời được lựa chọn liên quan đến việc lặp qua các kết quả. Nhưng có một giải pháp tốt hơn. stackoverflow.com/a/1197424/5079380
Amr ElAdawy

1
@DanHanly - về mặt kỹ thuật, truy vấn MYSQL (bằng PHP) trả về một chuỗi đại diện cho giá trị ô - giá trị ô thực tế được lưu trữ trong cơ sở dữ liệu cho số nguyên 32 bit là ... số nguyên 32 bit, không phải là một chuỗi chữ số .
ToolmakerSteve

Đối với tôi, khi tôi sử dụng, $conn->query("your query")tôi đã nhận được các trường số nguyên dưới dạng chuỗi nhưng khi tôi sử dụng $conn->prepare("your query")tôi đã nhận được các tham số như trong cơ sở dữ liệu
Bar Tzadok

Câu trả lời:


129

Khi bạn chọn dữ liệu từ cơ sở dữ liệu MySQL bằng PHP, kiểu dữ liệu sẽ luôn được chuyển đổi thành một chuỗi. Bạn có thể chuyển đổi nó trở lại một số nguyên bằng mã sau đây:

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

Hoặc bằng cách sử dụng chức năng intval():

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

79
Đến với MySQL từ nền tảng Postgres tôi cảm thấy cần phải nói rằng đây là một nỗi đau rất lớn ở mông. Khi bạn tìm nạp một hàng trong Postgres, bạn hãy chắc chắn rằng các phần tử trong mảng hàng có các kiểu dữ liệu phù hợp. Bây giờ tôi phải viết mã để truyền thủ công mọi phần tử vào kiểu dữ liệu mà tôi mong đợi.
GordonM

25
Tôi vừa thực hiện một số thử nghiệm trên Windows với Laravel và Mysql trên cùng một máy chủ cơ sở dữ liệu và lược đồ. Trên Windows, khóa chính được trả về dưới dạng Số nguyên và trên Linux, đó là Chuỗi.
AturSams

Ok đó là một ý tưởng tốt nhưng nếu bạn có hàng ngàn trường để lấy thì sao? Quá trình này mất một lúc .. Trong ví dụ của tôi, tôi lấy số lượt xem cho mỗi bài đăng, sau đó tôi in tất cả bài đăng của mình trong một bảng, tôi cho phép người dùng sắp xếp theo View asc và desc, nhưng nó sắp xếp theo "1" đến "9 "hoặc" 9 "đến" 1 "vì vậy ở vị trí đầu tiên bạn có thể có" 9999 "," 91 "," 8111 "," 7 ", v.v ...
KeizerBridge

@zehelvion bạn đã bao giờ tìm ra giải pháp cho vấn đề này chưa?
Felipe Francisco

2
Mỗi trường được trả về sẽ là một chuỗi HOẶC NULL .
Liam

73

Sử dụng mysqlnd (trình điều khiển gốc) cho php.

Nếu bạn đang sử dụng Ubuntu:

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

Nếu bạn đang ở trên Centos:

sudo yum install php-mysqlnd
sudo service httpd restart

Trình điều khiển riêng trả về các kiểu số nguyên một cách thích hợp.

Biên tập:

Như @Jeroen đã chỉ ra, phương pháp này sẽ chỉ hoạt động vượt trội cho PDO.
Như @LarsMoelleken đã chỉ ra, phương pháp này sẽ hoạt động với mysqli nếu bạn cũng đặt tùy chọn MYSQLI_OPT_INT_AND_FLOAT_NECT thành đúng.

Thí dụ:

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

Tôi không thấy bất kỳ bằng chứng nào về việc này. Chạy với mysqlnd và mysqli, các giá trị chuỗi rõ ràng được trả về.
Jeroen

@Jeroen bạn có chắc không? Có rất nhiều tài liệu có sẵn. stackoverflow.com/questions/1197005/
trộm

Đúng. Cũng nhìn vào các ý kiến ​​dưới đây. Bạn đã tự kiểm tra điều này? như hiện tại, thậm chí mysqlnd chỉ trả về các loại thích hợp nếu bạn sử dụng các câu lệnh đã chuẩn bị. ví dụ: $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);trả về: array(1) { ["CAST('3.51' AS DECIMAL(3,2))"]=> string(4) "3.51" }
Jeroen

1
Không phải tôi hiểu nó như thế nào, nó nên hoạt động như nhau với PDO và Mysqli. Ngay cả trên liên kết mà bạn đăng ở trên trong bình luận cũng có ghi rõ rằng nó CHỈ LÀM VIỆC VỚI TUYÊN BỐ ĐÃ CHUẨN BỊ và không truy vấn nội tuyến theo OP. trích dẫn từ trang đó: Nhưng đây chỉ là PHP 5.3 (với điều kiện phiên bản PHP 5.3 của bạn được biên dịch bằng mysqlnd (và không phải libmysql cũ)) và dường như chỉ là trường hợp cho các câu lệnh được chuẩn bị :-(
Jeroen

7
bạn cũng có thể sử dụng "MYSQLI_OPT_INT_AND_FLOAT_NECT" cho mysqli
Lars Moelleken

20

Giải pháp dễ nhất tôi tìm thấy:

Bạn có thể buộc json_encode sử dụng số thực cho các giá trị trông giống như số:

json_encode($data, JSON_NUMERIC_CHECK) 

(kể từ PHP 5.3.3).

Hoặc bạn chỉ có thể truyền ID của bạn đến một int.

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

1
Sử dụng một json_encodechuỗi để đúc để int nếu có thể cũng giống như sử dụng kính hiển vi để làm nghẹt móng.
LibertyPaul

7
Điều này sẽ phá vỡ tất cả các mã bưu điện và số điện thoại. Cách tốt để giới thiệu lỗi trong ứng dụng của bạn. Giải pháp PHẢI tôn trọng kiểu dữ liệu cột mysql, không cố gắng đoán từ giá trị.
Max Cuttins

1
Max Cuttins, quan điểm của bạn là hợp lệ. Tuy nhiên, nếu bạn có thể tính đến tất cả các loại dữ liệu dự kiến ​​từ DB, thì đây sẽ là một tuyến đường hoàn hảo để thực hiện.
Ifedi Okonkwo

1
Điều này sẽ làm tổn thương bạn khi bạn đôi khi có id của một số loại như '06'. Cờ này sẽ chuyển đổi nó thành 6. Điều này là sai vì những id đó nên giữ các số 0 ở cuối.
Hassan cha Khan

Đây là một giải pháp tuyệt vời cho các giá trị được tạo bởi UNIX_TIMESTAMP(), ví dụ.
David

18

Giải pháp của tôi là truyền kết quả truy vấn $rsvà nhận một mảng PGS của dữ liệu được truyền dưới dạng trả về:

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

Ví dụ sử dụng:

$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
Giải pháp tuyệt vời ngoại trừ 'NULL' cũng là một loại biến được sử dụng bởi hàm settype (). Vì vậy, mã của bạn thay đổi tất cả các giá trị NULL được cơ sở dữ liệu trả về (các giá trị trong đó gettype () == 'NULL') thành loại 'chuỗi' với '' value, 'số nguyên' với giá trị 0 hoặc loại 'float' với giá trị 0,0. Bạn không cần gọi settype nếu is_null ($ data [$ i] [$ name]) là đúng.
Rồng mùa đông

Tôi thích kỹ thuật của chủ mưu, nhưng mã hóa có thể đơn giản hơn .
ToolmakerSteve

13

Bất kể loại dữ liệu được xác định trong các bảng của bạn, trình điều khiển MySQL của PHP luôn phục vụ các giá trị hàng dưới dạng chuỗi.

Bạn cần truyền ID của bạn đến một int.

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

6
Không phải PHP chịu trách nhiệm (trực tiếp) cho hành vi này, đó là trình điều khiển cơ sở dữ liệu. Nếu bạn đang can thiệp vào cơ sở dữ liệu Postgres từ PHP, bạn sẽ nhận được các loại dữ liệu phù hợp.
GordonM

5

Tôi thích câu trả lời của Chad, đặc biệt là khi kết quả truy vấn sẽ được chuyển sang javascript trong trình duyệt. Javascript xử lý rõ ràng với các thực thể giống như số dưới dạng số nhưng yêu cầu thêm công việc để xử lý các thực thể giống như số dưới dạng chuỗi. tức là phải sử dụng parseInt hoặc parseFloat trên chúng.

Dựa trên giải pháp của Chad Tôi sử dụng giải pháp này và nó thường chính xác là những gì tôi cần và tạo các cấu trúc có thể được mã hóa JSON để dễ dàng xử lý trong javascript.

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

Việc thêm một chuỗi số vào 0 sẽ tạo ra một kiểu số trong PHP và xác định chính xác loại đó để các số dấu phẩy động sẽ không bị cắt thành các số nguyên.


5

Điều này xảy ra khi PDO::ATTR_EMULATE_PREPARESđược đặt thành truetrên kết nối.

Mặc dù cẩn thận, thiết lập nó để falsekhông cho phép sử dụng các tham số nhiều lần. Tôi tin rằng nó cũng ảnh hưởng đến chất lượng của các thông báo lỗi trở lại.


2

Bạn có thể làm điều này với ...

  1. mysql_fetch_field ()
  2. mysqli_result :: fetch_field_direct hoặc
  3. PDOStatement :: getColumnMeta ()

... Tùy thuộc vào tiện ích mở rộng bạn muốn sử dụng. Đầu tiên không được khuyến khích vì phần mở rộng mysql không được dùng nữa. Thứ ba vẫn là thử nghiệm.

Các ý kiến ​​tại các siêu liên kết này thực hiện tốt việc giải thích cách đặt loại của bạn từ một chuỗi cũ đơn giản thành loại ban đầu trong cơ sở dữ liệu.

Một số khung cũng trừu tượng hóa điều này (CodeIgniter cung cấp $this->db->field_data()).

Bạn cũng có thể thực hiện phỏng đoán - như lặp qua các hàng kết quả của mình và sử dụng is_numeric () trên mỗi hàng. Cái gì đó như:

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

Điều này sẽ biến bất cứ thứ gì trông giống như một số thành một ... chắc chắn không hoàn hảo.


Không hoạt động cho phao. Họ vượt qua bài kiểm tra is_numeric. Bạn nên kiểm tra phao trước.
Martin van Driel

@MartinvanDriel hoặc bất kỳ chuỗi nào chỉ chứa các số, nhưng phải là một chuỗi
Treeface

@MartinvanDriel Hãy thử thêm:if (is_float()) { $value = (float)$value; }
adjwilli

2

Trong dự án của tôi, tôi thường sử dụng một chức năng bên ngoài để "lọc" dữ liệu được lấy mysql_fetch_assoc.

Bạn có thể đổi tên các trường trong bảng để trực quan để hiểu loại dữ liệu nào được lưu trữ.

Ví dụ: bạn có thể thêm một hậu tố đặc biệt cho mỗi trường số: nếu useridlà một INT(11)bạn có thể đổi tên nó userid_ihoặc nếu đó là một hậu tố UNSIGNED INT(11)bạn có thể đổi tên userid_u. Tại thời điểm này, bạn có thể viết một hàm PHP đơn giản nhận đầu vào mảng kết hợp (được truy xuất mysql_fetch_assoc) và áp dụng truyền vào "giá trị" được lưu trữ với các "khóa" đặc biệt đó.


1

Nếu các câu lệnh được chuẩn bị được sử dụng, kiểu sẽ là int khi thích hợp. Mã này trả về một mảng các hàng, trong đó mỗi hàng là một mảng kết hợp. Giống như nếu fetch_assoc()được gọi cho tất cả các hàng, nhưng với thông tin loại được bảo tồn.

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 có trình điều khiển cho nhiều ngôn ngữ khác, chuyển đổi dữ liệu thành chuỗi "chuẩn hóa" dữ liệu và để người dùng chuyển các giá trị truyền sang int hoặc các ngôn ngữ khác


1
Tôi tin rằng các loại nguyên thủy là khá nhiều "tiêu chuẩn"? Nếu một trình điều khiển dành riêng cho ngôn ngữ không thể đáp ứng nhu cầu cho ngôn ngữ đó, tôi sẽ nói rằng điều đó rất đáng thất vọng
Chung

1

Trong trường hợp của tôi, mysqlnd.sophần mở rộng đã được cài đặt. NHƯNG tôi đã không pdo_mysqlnd.so. Vì vậy, vấn đề đã được giải quyết bằng cách thay thế pdo_mysql.sobằng pdo_mysqlnd.so.


0

Tôi thích kỹ thuật của chủ mưu , nhưng mã hóa có thể đơn giản hơn:

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

Tôi cũng đã thêm kiểm tra cho truy vấn trả về sai thay vì tập kết quả.
Và kiểm tra một hàng với một trường có giá trị null.
Và nếu loại mong muốn là một chuỗi, tôi sẽ không lãng phí bất kỳ thời gian nào trên chuỗi đó - đó đã là một chuỗi.


Tôi không bận tâm sử dụng điều này trong hầu hết các mã php; Tôi chỉ dựa vào chuyển đổi loại tự động của php. Nhưng nếu truy vấn nhiều dữ liệu, sau đó thực hiện tính toán số học, việc chuyển sang các loại tối ưu lên phía trước là điều hợp lý.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.