Saya ingin tahu apakah mungkin untuk mengikat array nilai ke placeholder menggunakan PDO. Use case di sini mencoba untuk melewatkan array nilai untuk digunakan dengan suatu IN()
kondisi.
Saya ingin dapat melakukan sesuatu seperti ini:
<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN(:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>
Dan minta PDO mengikat dan mengutip semua nilai dalam array.
Saat ini saya sedang melakukan:
<?php
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
foreach($ids as &$val)
$val=$db->quote($val); //iterate through array and quote
$in = implode(',',$ids); //create comma separated list
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN('.$in.')'
);
$stmt->execute();
?>
Yang pasti berhasil, tetapi hanya ingin tahu apakah ada solusi bawaan yang saya lewatkan?
Jawaban:
Saya pikir soulmerge benar. Anda harus membuat string-kueri.
fix: dan, kamu benar memperbaiki kode (meskipun tidak mengujinya)
sunting: baik chris (komentar) dan seseorang tidak disarankan menyarankan bahwa foreach-loop ...
... mungkin berlebihan, sehingga
foreach
loop dan$stmt->execute
bisa diganti dengan hanya ...(lagi, saya tidak mengujinya)
sumber
$foreach
danbindValue()
tidak diperlukan - jalankan dengan array. Misalnya:$stmt->execute($ids);
str_repeat('?,', count($array) - 1). '?';
Untuk sesuatu yang cepat:
sumber
$input_list = substr(str_repeat(',?', count($ids)), 1);
str_repeat('?,', count($ids) - 1) . '?'
. Satu panggilan fungsi kurang.execute
array idApakah penting menggunakan
IN
pernyataan? Coba gunakanFIND_IN_SET
op.Misalnya, ada permintaan di PDO seperti itu
Maka Anda hanya perlu mengikat array nilai, meledak dengan koma, seperti ini
dan sudah selesai.
UPD: Seperti yang ditunjukkan beberapa orang di komentar atas jawaban ini, ada beberapa masalah yang harus dinyatakan secara eksplisit.
FIND_IN_SET
tidak menggunakan indeks dalam tabel, dan masih belum diimplementasikan - lihat catatan ini di pelacak bug MYSQL . Terima kasih kepada @BillKarwin untuk pemberitahuannya.implode
Anda menggunakan simbol koma sebagai pemisah. Terima kasih kepada @VaL untuk catatannya.Baik, jika Anda tidak terlalu bergantung pada indeks dan tidak menggunakan string dengan koma untuk pencarian, solusi saya akan jauh lebih mudah, lebih sederhana, dan lebih cepat daripada solusi yang tercantum di atas.
sumber
... FIND_IN_SET(description,'simple,search')
akan berfungsi, tetapiFIND_IN_SET(description,'first value,text, with coma inside')
akan gagal. Jadi fungsi akan mencari"first value", "text", "with coma inside"
bukannya yang diinginkan"first value", "text, with coma inside"
Karena saya melakukan banyak pertanyaan dinamis, ini adalah fungsi pembantu super sederhana yang saya buat.
Gunakan seperti ini:
Mengembalikan string
:id1,:id2,:id3
dan juga memperbarui$bindArray
ikatan yang Anda perlukan saat saatnya menjalankan kueri. Mudah!sumber
Solusi dari EvilRygy tidak berhasil untuk saya. Di Postgres Anda dapat melakukan solusi lain:
sumber
ERROR: operator does not exist: integer = text
. Setidaknya Anda perlu menambahkan casting eksplisit.cara yang sangat bersih untuk postgres menggunakan postgres-array ("{}"):
sumber
Inilah solusi saya:
Perhatikan penggunaan array_values. Ini dapat memperbaiki masalah pemesanan utama.
Saya menggabungkan array id dan kemudian menghapus item duplikat. Saya punya sesuatu seperti:
Dan itu gagal.
sumber
$original_array
Tambahkan item sebelum array asli:array_unshift($original_array, new_unrelated_item);
Tambahkan item setelah array asli:array_push($original_array, new_unrelated_item);
Ketika nilai-nilai terikat, item new_unrelated akan ditempatkan di lokasi yang benar. Ini memungkinkan Anda untuk mencampur item Array dan non-array. `Saya memperpanjang PDO untuk melakukan sesuatu yang mirip dengan yang disarankan stefs, dan itu lebih mudah bagi saya dalam jangka panjang:
Anda bisa menggunakannya seperti ini:
sumber
:array
ada dalam string dalam kueri.if (is_array($data))
satu) tidak perlu namun membuat cara pemrosesan data lebih akurat.Melihat PDO: Konstanta yang Ditentukan sebelumnya tidak ada PDO :: PARAM_ARRAY yang Anda perlukan seperti yang tercantum di PDOStatement-> bindParam
Jadi saya pikir itu tidak mungkin.
sumber
Ketika Anda memiliki parameter lain, Anda dapat melakukan ini:
sumber
Bagi saya solusi yang lebih seksi adalah dengan membangun array asosiatif yang dinamis & menggunakannya
sumber
Saya juga menyadari bahwa utas ini sudah lama tetapi saya memiliki masalah unik di mana, ketika mengubah driver mysql yang akan segera ditinggalkan ke driver PDO saya harus membuat fungsi yang dapat membangun, secara dinamis, baik param normal dan INs dari yang sama. array param. Jadi saya cepat-cepat membangun ini:
Ini masih belum teruji namun nampaknya logika ada di sana.
Semoga ini membantu seseorang di posisi yang sama,
Sunting: Setelah beberapa pengujian saya menemukan:
Kode diedit ke versi yang berfungsi.
sumber
Sedikit mengedit tentang kode Schnalle
sumber
Database apa yang Anda gunakan? Di PostgreSQL saya suka menggunakan ANY (array). Jadi, gunakan kembali contoh Anda:
Sayangnya ini cukup non-portabel.
Pada basis data lain, Anda harus membuat keajaiban sendiri seperti yang disebutkan orang lain. Anda tentu ingin menempatkan logika itu ke dalam kelas / fungsi untuk membuatnya dapat digunakan kembali di seluruh program Anda, tentu saja. Lihatlah komentar pada
mysql_query
halaman di PHP.NET untuk beberapa pemikiran lebih lanjut tentang subjek dan contoh skenario ini.sumber
Setelah mengalami masalah yang sama, saya pergi ke solusi yang lebih sederhana (meskipun masih tidak seanggun
PDO::PARAM_ARRAY
):diberikan array
$ids = array(2, 4, 32)
:... dan seterusnya
Jadi jika Anda menggunakan array nilai campuran, Anda akan memerlukan lebih banyak kode untuk menguji nilai Anda sebelum menetapkan param tipe:
Tetapi saya belum menguji yang ini.
sumber
Seperti yang saya tahu tidak ada kemungkinan untuk mengikat array ke pernyataan PDO.
Tetapi ada 2 solusi umum:
Gunakan Placeholder Posisional (?,?,?,?) Atau Namholder Placeholder (: id1,: id2,: id3)
$ whereIn = implode (',', array_fill (0, count ($ ids), '?'));
Array kutipan sebelumnya
$ whereIn = array_map (array ($ db, 'quote'), $ ids);
Kedua opsi itu baik dan aman. Saya lebih suka yang kedua karena lebih pendek dan saya bisa parameter var_dump jika saya membutuhkannya. Menggunakan placeholder Anda harus mengikat nilai dan pada akhirnya kode SQL Anda akan sama.
Dan yang terakhir dan penting bagi saya adalah menghindari kesalahan "jumlah variabel terikat tidak cocok dengan jumlah token"
Doktrin ini adalah contoh bagus menggunakan placeholder placeholder, hanya karena memiliki kontrol internal atas parameter yang masuk.
sumber
Jika kolom hanya bisa berisi bilangan bulat, Anda mungkin bisa melakukan ini tanpa placeholder dan langsung memasukkan id dalam kueri. Anda hanya perlu membuang semua nilai array ke integer. Seperti ini:
Ini seharusnya tidak rentan terhadap injeksi SQL.
sumber
ini solusinya. Saya juga telah memperluas kelas PDO:
Berikut ini adalah contoh penggunaan untuk kode di atas:
Biarkan aku tahu apa yang Anda pikirkan
sumber
BindArrayParam
dalam array asosiatif karena Anda tampaknya membatasi ini untuk bilangan bulat.Tidak mungkin menggunakan array seperti itu di PDO.
Anda perlu membuat string dengan parameter (atau gunakan?) Untuk setiap nilai, misalnya:
:an_array_0, :an_array_1, :an_array_2, :an_array_3, :an_array_4, :an_array_5
Ini sebuah contoh:
Jika Anda ingin terus menggunakan
bindParam
, Anda dapat melakukan ini sebagai gantinya:Jika Anda ingin menggunakan
?
placeholder, Anda dapat melakukannya seperti ini:Jika Anda tidak tahu apakah
$ids
kosong, Anda harus mengujinya dan menangani kasing yang sesuai (mengembalikan array kosong, atau mengembalikan Objek Null, atau melempar pengecualian, ...).sumber
Saya mengambil sedikit lebih jauh untuk mendapatkan jawaban lebih dekat ke pertanyaan awal tentang menggunakan placeholder untuk mengikat params.
Jawaban ini harus membuat dua loop melalui array yang akan digunakan dalam kueri. Tapi itu memecahkan masalah memiliki penampung kolom lain untuk pertanyaan yang lebih selektif.
sumber
pertama-tama Anda menetapkan jumlah "?" dalam kueri dan kemudian oleh parameter "untuk" kirim parameter seperti ini:
sumber