【问题标题】:Why is PDO treating a blank value as null?为什么 PDO 将空白值视为空值?
【发布时间】:2014-12-16 18:41:30
【问题描述】:

我正在尝试在汽车表中插入一条记录。这是表格的精简版。

注意:这不是现实生活中的工作模型,不应该这样使用或评估。我只是以简化的方式显示我遇到的问题。

mysql> describe desc_autos;
+-----------------+------------------+------+-----+---------------------+----------------+
| Field           | Type             | Null | Key | Default             | Extra          |
+-----------------+------------------+------+-----+---------------------+----------------+
| car_id          | int(10) unsigned | NO   | PRI | NULL                | auto_increment |
| automobile_name | varchar(25)      | NO   | MUL |                     |                |
+-----------------+------------------+------+-----+---------------------+----------------+
7 rows in set (0.00 sec)

mysql> select count(*) FROM desc_autos WHERE automobile_name IS NULL;
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

mysql> select count(*) FROM desc_autos WHERE automobile_name = '';
+----------+
| count(*) |
+----------+
|    19322 |
+----------+
1 row in set (0.02 sec)

+-------------+
CREATE TABLE `desc_autos` (
  `car_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `automobile_name` varchar(15) NOT NULL,
  PRIMARY KEY (`car_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 |
+-------------+
1 row in set (0.00 sec)

所以您看到automobile_name 字段是NOT NULL,并且许多记录显示为空白值。 (忽略字段名称 - 只接受具有非空值的字段)

我正在从原生 MySQL 函数转换为 PDO。如果我插入一条具有非空白 automobile_name 值的记录,没问题 - 工作正常。如果automobile_name 为空白,PDO 会拒绝。

    $automobile_name = '';
    try 
    {
        $q = "
            INSERT INTO
                desc_autos
                (
                    automobile_name
                )
            VALUES
                (
                    :automobile_name
                )
        ";
        $stmt = $dbx_pdo->prepare($q);
        $stmt->bindParam(':automobile_name',    $automobile_name,   PDO::PARAM_STR);
        $stmt->execute();
        return true;
    } catch(PDOException $err) {
        log_error();
        return false;
    }       
}

这会导致以下错误:

Error: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'automobile_name' cannot be null

我认为我必须隐式告诉 PDO 插入一个 NULL 值,否则空白值将被插入为...空白值。

例如:

$stmt->bindValue(':automobile_name', !empty($automobile_name) ? $automobile_name : NULL, PDO::PARAM_STR);

在这种情况下,我不需要插入 NULL - 我需要在给定字段中删除一个空白的非空值。

问题:

为什么 PDO 将空白值视为空值?

【问题讨论】:

  • 您是否暗示IS NULL 与mysql_query() 一起使用?因为 PDO 并不真正影响 MySQL 表达式。至于插入,您将值与PDO::PARAM_STR 绑定,这会将 NULL 值转换为空白字符串。
  • @mario 我的反应也是,但顶部是$automobile_name = ''; 明确将其设置为空字符串。
  • @mario,在此之前插入查询看起来像$q = "INSERT INTO desc_autos (automobile_name) VALUES ( $automobile_name )"; 然后使用mysqli_query( $dbx, $q); 如果$automobile_name 为空白(甚至为null),它将作为空白值插入MySQL。
  • 好的。似乎我完全误解了你想要的东西。按照@MB 的建议选择非/隐式转换标志,尝试->bindValue(通常更好地保留类型),或调整您的表格方案(例如DEFAULT "" 或其他东西)。
  • @Mario 您能否添加有关更改表架构的答案?将 automobile_name 设置为接受 NULL 值消除了该错误。然后我使用UPDATE 将现有的空白值转换为NULL。这最初似乎解决了我的开发系统中的问题。 @MichaelBerkowski 也有一个很好的答案。

标签: php mysql pdo null


【解决方案1】:

听起来您需要将ATTR_ORACLE_NULLS(不管名称)设置为适当的设置,这样它就不会将空字符串转换为NULL。显然您的当前值为 PDO::NULL_EMPTY_STRING 导致空字符串 '' 为空。

// Set it to "natural" mode so NULLs and empty strings aren't modified
$dbx_pdo->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_NATURAL);

文档:PDO connection attributes

注意:根据我的快速测试,PDO::NULL_NATURAL 似乎是默认设置,但您的可能在其他地方被修改了。

根据您的SHOW CREATE TABLE 输出,automobile_name 列是NOT NULL,但没有明确定义默认值。我可能会采取将默认设置为空字符串'' 并允许PDO 插入NULL 的方法。正如马里奥在主评论线程中提到的那样:

ALTER TABLE desc_autos MODIFY `automobile_name` varchar(15) NOT NULL DEFAULT '';

在 PDOStatement bindParam() 中,您可以使用 PHP null 或空字符串 '' 来强制数据库使用其默认值。这将不需要更改您当前的行:

$stmt->bindParam(':automobile_name',    $automobile_name,   PDO::PARAM_STR);

【讨论】:

  • 虽然我不知道为什么会这样命名,但我可以在 oracle db 中确认,NULL == ''。当您习惯了其他数据库时,有时会很烦人。
  • 刚刚尝试过并继续收到错误 - 请参阅我对问题的评论以了解我之前使用的内容。看起来我需要根据@mario 修改表方案。
  • @acoder 您使用的是模拟准备还是真实准备?通过仿真,我可以通过修改这个 attr 将 NULL 转换为空字符串,但不能反过来(这就是你想要的)。有了真实的、非模拟的准备,我也无法有所作为。但是查看您的表格,您似乎已经将'' 作为默认值。可以发SHOW CREATE TABLE desc_autos吗?
  • 请注意,这现在可能已解决 - 我将 automobile_name 更改为在我的开发系统中接受空值,这消除了错误。
  • @acoder 好吧,如果您不想要空值,您仍然应该继续将其更改为 DEFAULT ''
猜你喜欢
  • 2019-08-21
  • 2017-08-28
  • 2021-05-11
  • 2014-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
相关资源
最近更新 更多