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

4

我是一个使用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] 的值有时为null。 如何将其插入数据库? 当我运行查询然后查看数据库中的数据时,此记录显示0.0000,而不是null。

如何使用PDO插入NULL值?提供了一些解决方案。

  • 我认为我不能像示例那样使用 $stmt->execute(array(':v1' => null, ':v2' => ...)) ,因为项目有时为空,有时不为空。 因此,我需要引用我创建的变量 $ fix ['FixPM'] [$i] 并在需要时将其设置为null

提前致谢。


在“Fixed”表模式中,“FixPM”字段是否可为空? - luchosrock
你好,我已经澄清了问题。表结构显示FixPM是可空的。 - Gravy
1
变量的值实际上是 NULL,还是字符串 'NULL',当将其转换为数值时将会转换为 0?PDO 应该正确处理真正的 NULL,但字符串会发生转换。 - Michael Berkowski
$fix ["FixPM"] [0] = null; 这并没有做任何事情(不好)。而 $fix ["FixPM"] [0] ='NULL'; 则转换为 0.00000(不好)。 - Gravy
实际的 NULL 值不起作用?我觉得很奇怪。要修复字符串,您需要像这样使用 ':fixPM' => strtoupper($fix['FixPM'][$i]) === 'NULL' ? NULL : $fix['FixPM'][$i], - Michael Berkowski
1个回答

7

在我的看法中,这似乎是PDO准备语句模拟中的一个未报告的错误:

  1. PDOStatement::execute()的实现最终会调用pdo_parse_params();

  2. 而该函数则会根据相关参数的数据类型(由PDOStatement::bindValue()PDOStatement::bindParam()$data_type参数指示——所有作为$input_parameters提供给PDOStatement::execute()的参数都被视为PDO::PARAM_STR,如该函数的文档所述),试图引用/转义值;

  3. 无论其是否为null,字符串类型的值都会通过调用相关数据库驱动程序的quoter()方法进行转义/引用:对于PDO_MySQL,即mysql_handle_quoter(),该方法(最终)将值传递给mysqlnd_cset_escape_quotes()mysql_cset_escape_slashes(),具体取决于服务器的NO_BACKSLASH_ESCAPES SQL模式;

  4. 如果传入了null参数,则这两个函数都会返回空字符串。

我的意见是,在上述步骤2中打开参数类型之前,pdo_parse_params() 应该将类型设置为 PDO::PARAM_NULL 如果值为 null。然而,有人可能会认为这会阻止适当处理特定类型的 null 值,在这种情况下,字符串情况 (在上述步骤3中) 应该在调用驱动程序的 quoter() 方法之前处理 null 值。
作为一个临时解决方法,禁用准备语句模拟通常是最好的:
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);

很好。非常详细和专注的回答! - dani herrera

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接