Bagaimana cara memasukkan nilai NULL menggunakan PDO?

105

Saya menggunakan kode ini dan saya sangat frustrasi:

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, '', semuanya gagal dan melempar kesalahan ini:

Kesalahan fatal : Tidak dapat melewatkan parameter 2 dengan referensi di / opt / ...

Nacho
sumber

Jawaban:

138

Saya baru belajar PDO, tapi saya pikir Anda perlu menggunakan bindValue, bukanbindParam

bindParammengambil variabel, untuk referensi, dan tidak menarik nilai pada saat memanggil bindParam. Saya menemukan ini di komentar di dokumen php:

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

EDIT: NB Anda mungkin tergoda untuk melakukan ini bindValue(':param', null, PDO::PARAM_NULL);tetapi itu tidak berhasil untuk semua orang (terima kasih Will Shaver untuk laporannya.)

JasonWoof
sumber
Saya tidak yakin perbedaan antara keduanya, tapi saya akan menyelidiki beberapa. Terima kasih, jawaban Anda juga bagus.
Nacho
3
Saya pikir ini mungkin jawaban yang lebih baik daripada saya (jika memang berhasil)
Joe Phillips
2
Saya mengalami masalah dengan PDO :: PARAM_NULL di MySql 5.1.53, tetapi PDO :: PARAM_INT dengan nilai null berfungsi dengan baik.
Will Shaver
2
Odin: Saya pikir bagian terpenting adalah melewatkan ketiga parameter :). dalam pertanyaan ign dia melewati PDO :: PARAM_NULL sebagai nilai, bukan sebagai tipe (dan tidak melewatkan tipe sama sekali.)
JasonWoof
1
FYI: dalam banyak kasus Anda benar-benar baik-baik saja dengan menggunakan bindValue()lebih bindParam(); untuk segalanya, bukan hanya untuk NULLnilainya. Saya tidak dapat memikirkan satu kasus di mana Anda perlu mengikat parameter ke referensi variabel PHP - tetapi itulah yang bindParam()dilakukannya.
low_rents
48

Saat menggunakan bindParam()Anda harus mengirimkan variabel, bukan konstanta. Jadi sebelum baris itu Anda perlu membuat variabel dan mengaturnya kenull

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

Anda akan mendapatkan pesan kesalahan yang sama jika Anda mencoba:

$stmt->bindParam(':v1', 5, PDO::PARAM_NULL);
Joe Phillips
sumber
Anda benar, saya baru menyadari bahwa saya telah melakukannya sebelumnya dalam kode saya, $ null = PDO :: PARAM_NULL; Terima kasih.
Nacho
1
Lebih baik menggunakan bindValue () dalam kasus ini, jika Anda tetap akan membuat placeholder. bindParam () awalnya dimaksudkan untuk menjalankan kueri, lalu mengubah variabel dan mengeksekusi ulang tanpa mengikat parameter lagi. bindValue () mengikat segera, bindParam () hanya saat dijalankan.
Hugo Zink
1
Saya menemukan bahwa null harus huruf kecil di baris $ myNull = null. $ myNull = NULL TIDAK berhasil.
raphael75
28

Saat menggunakan INTEGERkolom (bisa jadiNULL ) di MySQL, PDO memiliki beberapa perilaku yang tidak terduga (bagi saya).

Jika Anda menggunakan $stmt->execute(Array), Anda harus menentukan literal NULLdan tidak dapat memberikan NULLreferensi variabel. Jadi ini tidak akan berhasil:

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

Tapi ini akan berhasil:

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

Mencoba ini di MySQL 5.5.15 dengan PHP 5.4.1

ChrisF
sumber
1
$ stmt-> jalankan (array (': param' =>! empty ($ val)? $ val: null)); Gunakan! Kosong karena untuk string kosong Anda juga ingin mengatur null dalam database
Shehzad Nizamani
1
@ShehzadNizamani Hanya jika tipe kolomnya integer, seperti contoh nya ya. Tetapi sebaliknya isset()berkorelasi lebih baik dengan NULL. String kosong juga merupakan nilai.
StanE
8

Bagi mereka yang masih memiliki masalah (Tidak dapat melewatkan parameter 2 dengan referensi), tentukan variabel dengan nilai null, bukan hanya meneruskan null ke PDO:

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

Semoga ini membantu.

Pedro Guglielmo
sumber
6

Saya memiliki masalah yang sama dan saya menemukan solusi ini berfungsi dengan bindParam:

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

Jika Anda ingin menyisipkan NULLhanya jika valueadalah emptyatau '', tetapi sisipkanvalue jika tersedia.

A) Menerima data formulir menggunakan metode POST, dan fungsi panggilan dimasukkan dengan nilai-nilai tersebut.

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

B) Mengevaluasi jika bidang tidak diisi oleh pengguna, dan menyisipkan NULLjika demikian.

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

Misalnya, jika pengguna tidak memasukkan apa pun di productNamebidang formulir, maka $productNameakan SETtetapi EMPTY. Jadi, Anda perlu memeriksa apakah benar empty(), dan jika ya, maka masukkan NULL.

Diuji pada PHP 5.5.17

Semoga berhasil,

Arian Acosta
sumber
3
Atau, Anda dapat menggunakan IFNULL()fungsi MySQL dalam string kueri. Seperti ini:$sql = "INSERT INTO products ( productId, productName ), VALUES ( IFNULL(:productId, NULL), IFNULL(:productName, NULL) )";
starleaf1
Saya suka kebersihan solusi Anda. Saya baru saja mengujinya, tetapi sayangnya itu menyisipkan string kosong alih-alih NULL ketika pengguna tidak menulis apa pun pada input. Ini hanya masalah preferensi, tetapi saya lebih memilih NULL daripada string kosong.
Arian Acosta
0

Coba ini.

$stmt->bindValue(':v1', null, PDO::PARAM_NULL); // --> insert null
hector teran
sumber
1
Sebelum mencoba menjawab pertanyaan lama seperti itu, Anda harus membaca jawaban lain terlebih dahulu. Mungkin sudah terjawab.
Akal Sehat Anda
0

Berdasarkan jawaban lain tetapi dengan sedikit kejelasan tentang bagaimana sebenarnya menggunakan solusi ini.

Jika misalnya Anda memiliki string kosong untuk nilai waktu tetapi Anda ingin menyimpannya sebagai null:

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

Perhatikan bahwa untuk nilai waktu Anda akan menggunakan PARAM_STR, karena waktu disimpan sebagai string.

Vincent
sumber
-1

Dalam kasus saya, saya menggunakan:

  • SQLite,

  • pernyataan yang disiapkan dengan placeholder untuk menangani jumlah bidang yang tidak diketahui,

  • Permintaan AJAX dikirim oleh pengguna di mana semuanya adalah string dan tidak ada yang namanya NULLnilai dan

  • Saya sangat perlu memasukkan NULLs karena itu tidak melanggar batasan kunci asing (nilai yang dapat diterima).

Misalkan, sekarang pengguna mengirim dengan post: $_POST[field1]dengan nilai value1yang bisa berupa string kosong ""atau "null"atau "NULL".

Pertama saya membuat pernyataan:

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

dimana {$sColumns}sth seperti field1, field2, ...dan {$sValues}placeholder saya ?, ?, ....

Kemudian, saya mengumpulkan $_POSTdata saya yang terkait dengan nama kolom dalam array $values dan mengganti dengan NULLs:

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

Sekarang, saya bisa mengeksekusi:

$stmt->execute($values);

dan di antara batasan kunci asing lainnya.

Jika di sisi lain, string kosong lebih masuk akal maka Anda harus memeriksa apakah bidang itu adalah bagian dari kunci asing atau bukan (lebih rumit).

centurian
sumber