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中考虑到这一点
丹汉利

如果您需要列类型,请参见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")参数时,它们却
保留

Answers:


129

当您使用PHP从MySQL数据库中选择数据时,数据类型将始终转换为字符串。您可以使用以下代码将其转换回整数:

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

或使用功能intval()

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

79
我是从Postgres的背景来到MySQL的,我觉得有必要说,这是一个巨大的痛苦。当您在Postgres中获取一行时,请确保该行数组中的元素具有适当的数据类型。现在,我不得不编写代码以将每个元素手动转换为期望的数据类型。
GordonM 2011年

25
我只是在Windows和Windows Server上使用相同的架构和数据库服务器上的Laravel和Mysql进行了一些测试。在Windows上,主键作为整数返回,而在Linux上,它是字符串。
AturSams,2014年

好的,这是个好主意,但是如果要检索成千上万个字段怎么办?此过程需要一段时间。.在我的示例中,我检索每个帖子的视图数,然后将所有帖子打印在一个表中,我允许用户按View asc和desc进行排序,但按“ 1”到“ 9”排序”或“ 9”到“ 1”,因此第一位可以有“ 9999”,“ 91”,“ 8111”,“ 7”等...
KeizerBridge

@zehelvion您是否找到了解决方案?
费利佩·弗朗西斯科

2
返回的每个字段都是字符串OR NULL
利亚姆

73

对php使用mysqlnd(本机驱动程序)。

如果您使用的是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_OPT_INT_AND_FLOAT_NATIVE选项设置为true,则此方法将与mysqli一起使用。

例:

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

我看不出这种说法的任何证据。与mysqlnd和mysqli一起运行时,显然会返回字符串值。
Jeroen 2014年

@耶伦你确定吗?有大量可用的文档。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 2014年

1
我不怎么理解它,它应该与PDO和Mysqli一样工作。即使在上面您在评论中发布的链接上,也清楚地指出,它仅适用于预声明,而不是按照OP的内联查询。该页面的引文:但这仅是PHP 5.3(前提是您的PHP 5.3版本是使用mysqlnd编译的(而不是旧的libmysql)),并且似乎仅适用于已准备好的语句:-(
Jeroen

7
您还可以对mysqli使用“ MYSQLI_OPT_INT_AND_FLOAT_NATIVE”
Lars Moelleken '16

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如果可能的话,使用a 将字符串转换为int就像使用显微镜将指甲cho住。
自由保​​罗'17

7
这将破坏所有邮政编码和电话号码。在您的应用中引入错误的好方法。解决方案必须尊重mysql列数据类型,而不要尝试从值中猜测。
Max Cuttins

1
Max Cuttins,您的观点是正确的。但是,如果您可以考虑数据库中期望的所有数据类型,那么这将是一条完美的选择。
Ifedi Okonkwo

1
当您有时使用类似'06'之类的ID时,这会对您造成伤害。该标志会将其转换为6。这是错误的,因为这些ID应当保持尾随零。
哈桑·爸爸汗

UNIX_TIMESTAMP()例如,对于由创建的值,这是一个很好的解决方案。
David

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'的值)更改为带有“值”的“字符串”类型,带有0值的“整数”类型或带有0.0值的“浮点”类型。如果is_null($ data [$ i] [$ name])为true,则无需调用settype。
Winter Dragoness

我喜欢mastermind的技术,但是编码可以更简单
ToolmakerSteve

13

否。不管表中定义的数据类型如何,PHP的MySQL驱动程序始终将行值用作字符串。

您需要将ID转换为int。

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

6
不是PHP直接(直接)负责这种行为,而是数据库驱动程序。如果您要通过PHP与Postgres数据库进行连接,则会获得适当的数据类型。
GordonM 2011年

5

我喜欢乍得的答案,尤其是当查询结果将传递到浏览器中的javascript时。Javascript干净地处理诸如数字之类的数字实体,但需要额外的工作来处理诸如字符串之类的数字实体。即必须在它们上使用parseInt或parseFloat。

在Chad的解决方案的基础上,我使用了它,通常正是我所需要的,并创建了可以JSON编码的结构,以便在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;
    }
}

将数字字符串添加到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 '16

@MartinvanDriel尝试添加:if (is_float()) { $value = (float)$value; }
adjwilli 2016年

2

在我的项目中,我通常使用一个外部函数来“过滤”使用 mysql_fetch_assoc

您可以重命名表中的字段,以便直观了解要存储的数据类型。

例如,您可以在每个数字字段中添加一个特殊的后缀:如果userid为,则INT(11)可以对其进行重命名;userid_i如果为,则UNSIGNED INT(11)可以对其进行重命名userid_u。此时,您可以编写一个简单的PHP函数,以接收关联数组(用检索到mysql_fetch_assoc)作为输入,并将强制转换应用于那些特殊“键”所存储的“值”。


1

如果使用了预准备语句,则在适当的地方类型将为int。此代码返回一个行数组,其中每一行都是一个关联数组。就像if 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具有许多其他语言的驱动程序,可将数据转换为字符串“标准化”数据,并留给用户将类型转换为int或其他值


1
我相信原始类型几乎是“标准”吗?如果特定语言的驱动程序不能满足该语言的需求,我会说这非常令人失望
Chung

1

就我而言,mysqlnd.so已安装扩展程序。但是我没有pdo_mysqlnd.so。因此,该问题已通过替换pdo_mysql.so为解决pdo_mysqlnd.so


0

我喜欢mastermind的技术,但是编码可以更简单:

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

我还添加了查询返回false而不是结果集的查询。
并检查包含字段为空值的行。
而且,如果所需的类型是字符串,那么我不会在上面浪费任何时间-它已经是字符串。


我不用在大多数php代码中使用它;我只是依靠php的自动类型转换。但是,如果查询大量数据,然后执行算术计算,则先将类型强制转换为最佳类型是明智的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.