Làm cách nào để chèn giá trị NULL bằng PDO?


105

Tôi đang sử dụng mã này và tôi không khỏi thất vọng:

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, '', tất cả chúng đều không thành công và gặp lỗi này:

Lỗi nghiêm trọng : Không thể chuyển tham số 2 bằng tham chiếu trong / opt / ...

Câu trả lời:


138

Tôi chỉ học PDO, nhưng tôi nghĩ rằng bạn cần phải sử dụng bindValue, khôngbindParam

bindParamnhận một biến để tham chiếu và không kéo giá trị vào thời điểm gọi bindParam. Tôi tìm thấy điều này trong một bình luận trên tài liệu php:

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

CHỈNH SỬA: Tái bút Bạn có thể bị cám dỗ để làm điều này bindValue(':param', null, PDO::PARAM_NULL);nhưng nó không hiệu quả với tất cả mọi người (cảm ơn bạn Will Shaver đã báo cáo.)


Tôi không chắc sự khác biệt giữa hai điều đó, nhưng tôi sẽ điều tra một số. Cảm ơn, câu trả lời của bạn cũng rất tuyệt.
Nacho

3
Tôi nghĩ rằng đây có thể là một câu trả lời tốt hơn so với mỏ (nếu nó thực sự hoạt động)
Joe Phillips

2
Tôi đã gặp sự cố với PDO :: PARAM_NULL trên MySql 5.1.53, nhưng PDO :: PARAM_INT với giá trị null hoạt động tốt.
Will Shaver

2
Odin: Tôi nghĩ phần quan trọng nhất là truyền cả ba tham số :). trong câu hỏi IGN của ông đã đi qua PDO :: PARAM_NULL như giá trị, thay vì như các loại (và không phải đi qua một loại ở tất cả.)
JasonWoof

1
FYI: trong hầu hết các trường hợp, bạn hoàn toàn ổn khi sử dụng bindValue()hết bindParam(); cho mọi thứ, không chỉ cho NULLgiá trị. Tôi không thể nghĩ ra một trường hợp nào mà bạn cần phải liên kết tham số với một tham chiếu của một biến PHP - nhưng đó là những gì bindParam().
low_rents

48

Khi sử dụng, bindParam()bạn phải truyền vào một biến, không phải là một hằng số. Vì vậy, trước dòng đó, bạn cần tạo một biến và đặt nó thànhnull

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

Bạn sẽ nhận được thông báo lỗi tương tự nếu bạn đã thử:

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

Bạn hiểu đúng, tôi chỉ nhận ra rằng tôi đã làm điều đó trước đây trong mã của mình, $ null = PDO :: PARAM_NULL; cảm ơn.
Nacho

1
Tốt hơn là sử dụng bindValue () trong trường hợp này, nếu bạn vẫn định tạo trình giữ chỗ. bindParam () ban đầu nhằm thực thi một truy vấn, sau đó thay đổi các biến và thực thi lại mà không ràng buộc các tham số một lần nữa. bindValue () liên kết ngay lập tức, bindParam () chỉ khi thực thi.
Hugo Zink

1
Tôi thấy rằng null phải là chữ thường trong dòng $ myNull = null. $ myNull = NULL KHÔNG hoạt động.
raphael75,

27

Khi sử dụng INTEGERcột (có thể làNULL ) trong MySQL, PDO có một số hành vi không mong muốn (đối với tôi).

Nếu bạn sử dụng $stmt->execute(Array), bạn phải chỉ định nghĩa đen NULLvà không thể cung cấp NULLbằng tham chiếu biến. Vì vậy, điều này sẽ không hoạt động:

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

Nhưng điều này sẽ hoạt động:

// $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

Đã thử điều này trên MySQL 5.5.15 với PHP 5.4.1


1
$ stmt-> execute (array (': param' =>! blank ($ val)? $ val: null)); Sử dụng sản phẩm nào bởi vì đối với chuỗi rỗng bạn cũng sẽ muốn thiết lập null trong cơ sở dữ liệu!
Shehzad Nizamani

1
@ShehzadNizamani Chỉ khi loại cột là số nguyên, giống như trong ví dụ của anh ấy, có. Nhưng nếu không thì isset()tương quan tốt hơn với NULL. Một chuỗi rỗng cũng là một giá trị.
StanE

8

Đối với những người vẫn gặp sự cố (Không thể truyền tham số 2 bằng tham chiếu), hãy xác định một biến có giá trị null, không chỉ truyền null cho PDO:

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

Hi vọng điêu nay co ich.


6

Tôi đã gặp vấn đề tương tự và tôi thấy giải pháp này hoạt động với bindParam:

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

3

Nếu bạn chỉ muốn chèn NULLkhi valueemptyhoặc '', nhưng hãy chèn valuekhi có sẵn.

A) Nhận dữ liệu biểu mẫu bằng phương thức POST và gọi hàm chèn với các giá trị đó.

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

B) Đánh giá nếu một trường không được người dùng điền vào và chèn NULLnếu trường hợp đó xảy ra.

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

Ví dụ: nếu người dùng không nhập bất kỳ thứ gì vào productNametrường của biểu mẫu, thì $productNamesẽ là SETnhưng EMPTY. Vì vậy, bạn cần kiểm tra xem nó có đúng không empty(), và nếu có thì hãy chèn vào NULL.

Đã thử nghiệm trên PHP 5.5.17

Chúc may mắn,


3
Hoặc, bạn có thể sử dụng IFNULL()hàm của MySQL trong chuỗi truy vấn. Như thế này:$sql = "INSERT INTO products ( productId, productName ), VALUES ( IFNULL(:productId, NULL), IFNULL(:productName, NULL) )";
starleaf1

Tôi thích sự sạch sẽ của giải pháp của bạn. Tôi vừa thử nghiệm nó, nhưng thật không may, nó chèn các chuỗi trống thay vì NULL khi người dùng không viết bất cứ điều gì trên đầu vào. Đó chỉ là vấn đề sở thích, nhưng tôi muốn có NULL thay vì chuỗi rỗng.
Arian Acosta

0

Thử cái này.

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

1
Trước khi cố gắng trả lời một câu hỏi cũ như vậy, bạn nên đọc các câu trả lời khác trước. Có thể nó đã được trả lời.
bạn Common Sense

0

Dựa trên các câu trả lời khác nhưng rõ ràng hơn một chút về cách thực sự sử dụng giải pháp này.

Ví dụ: nếu bạn có một chuỗi trống cho một giá trị thời gian nhưng bạn muốn lưu nó dưới dạng null:

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

Lưu ý rằng đối với các giá trị thời gian, bạn sẽ sử dụng PARAM_STR, vì thời gian được lưu trữ dưới dạng chuỗi.


-1

Trong trường hợp của tôi, tôi đang sử dụng:

  • SQLite,

  • các câu lệnh đã chuẩn bị sẵn với trình giữ chỗ để xử lý số lượng trường không xác định,

  • Yêu cầu AJAX được gửi bởi người dùng trong đó mọi thứ đều là một chuỗi và không có thứ như NULLgiá trị và

  • Tôi thực sự cần phải chèn NULLs vì điều đó không vi phạm các ràng buộc khóa ngoại (giá trị chấp nhận được).

Giả sử, bây giờ người dùng gửi với bài đăng: $_POST[field1]với giá trị value1có thể là chuỗi trống ""hoặc "null"hoặc "NULL".

Đầu tiên tôi đưa ra tuyên bố:

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

nơi {$sColumns}là sth như field1, field2, ...{$sValues}là placeholders của tôi?, ?, ... .

Sau đó, tôi thu thập $_POSTdữ liệu của mình có liên quan đến tên cột trong một mảng $values thay thế bằng NULLs:

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

Bây giờ, tôi có thể thực hiện:

$stmt->execute($values);

và trong số các ràng buộc khóa ngoại khác bỏ qua.

Mặt khác, nếu một chuỗi rỗng có ý nghĩa hơn thì bạn phải kiểm tra xem trường đó có phải là một phần của khóa ngoại hay không (phức tạp hơn).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.