如何使用PDO插入NULL值?


105

我正在使用此代码,但我感到无奈:

try {
    $dbh = new PDO('mysql:dbname=' . DB . ';host=' . HOST, USER, PASS);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $dbh->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
}
catch(PDOException $e)
{
    ...
}
$stmt = $dbh->prepare('INSERT INTO table(v1, v2, ...) VALUES(:v1, :v2, ...)');
$stmt->bindParam(':v1', PDO::PARAM_NULL); // --> Here's the problem

PDO::PARAM_NULL, null, '', 它们全部失败并抛出此错误:

致命错误:无法在/ opt / ...中通过引用传递参数2

Answers:


138

我只是在学习PDO,但我认为您需要使用bindValue,而不是bindParam

bindParam接受要引用的变量,并且在调用时不提取值bindParam。我在对php文档的评论中发现了这一点:

bindValue(':param', null, PDO::PARAM_INT);

编辑:PS您可能会很想这样做,bindValue(':param', null, PDO::PARAM_NULL);但是它并不适合每个人(感谢Will Shaver的汇报。)


我不确定这两者之间的区别,但我将进行一些调查。谢谢,您的回答也很棒。
纳乔(Nacho)2009年

3
我认为这可能比我的答案更好(如果确实可行)
Joe Phillips

2
我在MySql 5.1.53上使用PDO :: PARAM_NULL遇到了麻烦,但是具有空值的PDO :: PARAM_INT的效果很好。
将于

2
奥丁:我认为最重要的部分是传递所有三个参数:)。在IGN的问题,他是路过PDO :: PARAM_NULL的价值,而不是作为类型(和所有不通过一个类型。)
JasonWoof

1
仅供参考:在大多数情况下,使用bindValue()over 可以完全解决问题bindParam();为了一切,而不仅仅是为了NULL价值。我想不出一种情况,您需要将参数绑定到PHP变量的引用-但这就是这样bindParam()做的。
low_rents 2015年

48

使用时,bindParam()您必须传入变量,而不是常量。因此,在该行之前,您需要创建一个变量并将其设置为null

$myNull = null;
$stmt->bindParam(':v1', $myNull, PDO::PARAM_NULL);

如果您尝试以下操作,则会收到相同的错误消息:

$stmt->bindParam(':v1', 5, PDO::PARAM_NULL);

没错,我只是意识到我之前在代码中已经做到了,$ null = PDO :: PARAM_NULL; 谢谢。
拿破仑

1
在这种情况下,最好还是使用bindValue(),否则无论如何都要使用占位符。bindParam()最初旨在执行查询,然后更改变量并重新执行而无需再次绑定参数。bindValue()立即绑定,bindParam()仅在执行时绑定。
雨果·辛克

1
我发现$ myNull = null行中null必须是小写。$ myNull = NULL不起作用。
raphael75 '17

28

在MySQL中使用INTEGER列(可以是NULL)时,PDO有一些(对我而言)意外的行为。

如果使用$stmt->execute(Array),则必须指定文字,NULL并且不能通过NULL变量引用给出。所以这行不通:

// $val is sometimes null, but sometimes an integer
$stmt->execute(array(
    ':param' => $val
));
// will cause the error 'incorrect integer value' when $val == null

但这将起作用:

// $val again is sometimes null, but sometimes an integer
$stmt->execute(array(
    ':param' => isset($val) ? $val : null
));
// no errors, inserts NULL when $val == null, inserts the integer otherwise

在MySQL 5.5.15和PHP 5.4.1上进行了尝试


1
$ stmt-> execute(array(':param'=>!empty($ val)?$ val:null)); 使用!empty,因为对于空字符串,您还希望在数据库中设置null
Shehzad Nizamani

1
@ShehzadNizamani仅当列类型是整数(如他的示例)时,才是。但是isset()与关联更好NULL。空字符串也是一个值。
StanE

8

对于仍然存在问题(无法通过引用传递参数2)的人,请定义一个具有空值的变量,而不仅仅是将空值传递给PDO:

bindValue(':param', $n = null, PDO::PARAM_INT);

希望这可以帮助。


6

我有同样的问题,我发现此解决方案可用于bindParam:

    bindParam(':param', $myvar = NULL, PDO::PARAM_INT);

3

如果只想NULLvalueis empty或时''插入,而在value可用时插入。

A)使用POST方法接收表单数据,并使用这些值调用函数insert。

insert( $_POST['productId'], // Will be set to NULL if empty    
        $_POST['productName'] ); // Will be to NULL if empty                                

B)评估用户是否未填写字段,NULL如果是,则插入。

public function insert( $productId, $productName )
{ 
    $sql = "INSERT INTO products (  productId, productName ) 
                VALUES ( :productId, :productName )";

    //IMPORTANT: Repace $db with your PDO instance
    $query = $db->prepare($sql); 

    //Works with INT, FLOAT, ETC.
    $query->bindValue(':productId',  !empty($productId)   ? $productId   : NULL, PDO::PARAM_INT); 

    //Works with strings.
    $query->bindValue(':productName',!empty($productName) ? $productName : NULL, PDO::PARAM_STR);   

    $query->execute();      
}

例如,如果用户未productName在表单字段中输入任何内容,$productName则将为SETbut EMPTY。因此,您需要检查它是否为empty(),如果是,则插入NULL

在PHP 5.5.17上测试

祝好运,


3
或者,您可以IFNULL()在查询字符串中使用MySQL的函数。像这样:$sql = "INSERT INTO products ( productId, productName ), VALUES ( IFNULL(:productId, NULL), IFNULL(:productName, NULL) )";
starleaf1 2014年

我喜欢清洁您的解决方案。我刚刚对其进行了测试,但是不幸的是,当用户未在输入中编写任何内容时,它会插入空字符串而不是NULL。这只是一个偏好问题,但是我宁愿使用NULL而不是空字符串。
阿里安·阿科斯塔

0

试试这个。

$stmt->bindValue(':v1', null, PDO::PARAM_NULL); // --> insert null

1
在尝试回答这样一个古老的问题之前,您应该先阅读其他答案。可能已经回答了。
常识

0

基于其他答案,但对如何实际使用此解决方案更加清楚。

例如,如果您有一个空字符串作为时间值,但您想将其保存为null:

  if($endtime == ""){
    $db->bind(":endtime",$endtime=NULL,PDO::PARAM_STR);
  }else{
    $db->bind("endtime",$endtime);
  }

请注意,对于时间值,您将使用PARAM_STR,因为时间存储为字符串。


-1

就我而言,我正在使用:

  • SQLite,

  • 与占位符一起准备的语句,用于处理未知数量的字段,

  • 用户发送的AJAX请求,其中所有内容都是字符串,并且没有诸如NULLvalue和

  • 我非常需要插入NULLs,因为这不会违反外键约束(可接受的值)。

假设,现在用户使用post:发送,$_POST[field1]其值value1可以是空字符串"""null"or "NULL"

首先,我声明:

$stmt = $this->dbh->prepare("INSERT INTO $table ({$sColumns}) VALUES ({$sValues})");

这里{$sColumns}是某事像field1, field2, ...{$sValues}是我的占位符?, ?, ...

然后,我收集$_POST与数组中的列名相关的数据,$values NULLs 代替:

  for($i = 0; $i < \count($values); $i++)
     if((\strtolower($values[$i]) == 'null') || ($values[$i] == ''))
        $values[$i] = null;

现在,我可以执行:

$stmt->execute($values);

以及其他绕过外键约束。

另一方面,如果使用空字符串确实有意义,那么您必须检查该字段是否为外键的一部分(更复杂)。

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.