调试 PDO mySql 将 NULL 插入数据库而不是空

Posted

技术标签:

【中文标题】调试 PDO mySql 将 NULL 插入数据库而不是空【英文标题】:Debug PDO mySql insert NULL into database instead of empty 【发布时间】:2012-12-06 04:00:05 【问题描述】:

我正在尝试使用 PDO 将“NULL”动态插入到数据库中。

表结构:

CREATE TABLE IF NOT EXISTS `Fixes` (
  `Id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'PK',
  `CurrencyId` int(11) NOT NULL COMMENT 'FK',
  `MetalId` int(11) NOT NULL COMMENT 'FK',
  `FixAM` decimal(10,5) NOT NULL,
  `FixPM` decimal(10,5) DEFAULT NULL,
  `TimeStamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`Id`),
  KEY `CurrencyId` (`CurrencyId`),
  KEY `MetalId` (`MetalId`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=13 ;

php/PDO 查询:

$sql = 'UPDATE 
            Fixes
    SET 
            FixAM = :fixAM,
        FixPM = :fixPM
        WHERE
            MetalId IN (SELECT Id FROM Metals WHERE Name = :metal) AND
        CurrencyId IN (SELECT Id FROM Currencies Where Id = :currency)';

$stmt = $db->prepare($sql); 

for ($i = 0; $i<3; $i++)   
    $stmt->execute(array(
    ':metal' => 'Silver', 
    ':fixAM' => $fix['FixAM'][$i], 
    ':fixPM' => $fix['FixPM'][$i],
    ':currency' => ($i+1))
    );      

例如有时,$fix['FixPM'][$i] 的值是sometimes'NULL'。如何将其插入数据库?当我运行查询然后查看数据库中的数据时,这条记录显示的是 0.0000,而不是 null。

How do I insert NULL values using PDO? 提供了一些解决方案。

我认为我不能按照示例使用$stmt-&gt;execute(array( ':v1' =&gt; null, ':v2' =&gt; ... )),因为有时该项目为空,有时则不是。因此,我需要引用我创建的变量 $fix['FixPM'][$i] 并在需要时将其设为 null

提前致谢。

【问题讨论】:

FixPM 字段在 Fixed 表架构中是否可以为空? 您好,我已经澄清了这个问题。表结构显示 FixPM 可以为空。 变量的值实际上是NULL,还是字符串 'NULL',当转换为数值时将转换为0? PDO 应该正确处理真正的NULL,但字符串会被强制转换。 $fix["FixPM"][0] = null;这没有做任何事情(不好)。和 $fix["FixPM"][0] = 'NULL';转换为 0.00000(不好) 实际的NULL值不起作用?我觉得这很奇怪。要修复字符串,您需要':fixPM' =&gt; strtoupper($fix['FixPM'][$i]) === 'NULL' ? NULL : $fix['FixPM'][$i], 【参考方案1】:

在我看来,这似乎是 PDO 准备好的语句模拟中的一个(n 未报告?)错误:

    PDOStatement::execute() 的implementation eventually 调用pdo_parse_params()

    反过来,attempts to quote/escape values 基于相关参数的数据类型(如 PDOStatement::bindValue()PDOStatement::bindParam()$data_type 参数所示 - 所有参数均以 $input_parametersPDOStatement::execute() 的形式提供被视为PDO::PARAM_STR,如该函数的文档中所述);

    字符串类型的值被calling相关数据库驱动程序的quoter()方法转义/引用,无论它们是否为null:在PDO_mysql的情况下,即mysql_handle_quoter(),(最终)将值传递给mysqlnd_cset_escape_quotes()mysql_cset_escape_slashes(),具体取决于服务器的NO_BACKSLASH_ESCAPES SQL 模式;

    给定一个 null 参数,这两个函数都返回一个空字符串。

我的意见是,在switching on the parameter's type 之前(在上面的步骤2 中),如果值为nullpdo_parse_params() 应该将类型设置为PDO::PARAM_NULL。但是,有些人可能会争辩说,这会在适当的情况下阻止对 null 值的特定类型处理,在这种情况下,string case(在上面的步骤 3 中)肯定应该在继续调用驱动程序的 @ 之前处理 null 值987654356@方法。

作为临时解决方法,禁用准备好的语句模拟通常是最好的:

$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);

【讨论】:

不错。非常详细和重点突出的答案!

以上是关于调试 PDO mySql 将 NULL 插入数据库而不是空的主要内容,如果未能解决你的问题,请参考以下文章

PDO 将一个简单的数组插入 MySQL 数据库

将多个复选框插入 MySQL (PDO)

使用 PDO 和 PHP 将表单中的数据插入 MySQL 数据库

使用 PDO 将 JSON 解码数据插入 mysql

使用 PDO 从 php 页面将具有更多列的表单数据插入 mysql 数据库

无法使用 PDO 插入 MySQL 数据库....没有错误