简体   繁体   中英

zend framework: how to prepare and execute WHERE IN clause?

I want to prepare a statement for use inside a loop. When I try to execute the statement I see an error in the logs saying "Invalid parameter number: no parameters were bound'".

What's wrong with my code?

$itemSelectSql = "SELECT * FROM `tblItems` WHERE `itemID` IN (?)";
$itemSelectStmt = new Zend_Db_Statement_Mysqli($this->db_ro, $itemSelectSql);
while () {
  ...
  $itemIds = array();
  // populate $itemIds array
  ...
  $itemSelectStmt->execute(array($itemIds));
}

EDIT:

I think I may have a bug in my set up which explains why whatever I try fails. I'm seeing this:

PHP Warning:  call_user_func_array() expects parameter 1 to be a valid callback, 
class 'PDOStatement' does not have a method 'bind_param' in 
/var/www/lib/Zend/Db/Statement/Mysqli.php on line 204

EDIT:

I was using the wrong adapter. Should have been Zend_Db_Statement_Pdo:-)

Thanks for the replies.

? can't be replaced by an array, it has to be replaced by a scalar (thanks to comment for pointing out that this does not always mean string... brain-fart on my end). Let me know if this works better:

$itemSelectSql = "SELECT * FROM `tblItems` WHERE `itemID` IN ";
while () {
  ...
  $itemIds = array();
  // populate $itemIds array
  ...
  // we need to have the same number of "?,"'s as there are items in the array.
  // and then remove final comma.
  $qs = rtrim(str_repeat("?,", count($itemIds)),',');
  // create a statement based on the result
  $itemSelectStmt = 
       new Zend_Db_Statement_Mysqli($this->db_ro, "$itemSelectSql ($qs)");
  // bind to each of those commas.
  $itemSelectStmt->execute($itemIds);
}

Have you tried doing this:

while () {
  ...
  $itemIds = array();
  // populate $itemIds array
  $itemIds = implode(',' $itemIds);
  $itemSelectStmt->execute(array($itemIds));
}

I'm not an expert of Zend_framework, but when you use statements, to the execute method you must

If you use positional parameters, or those that are marked with a question mark symbol ('?'), pass the bind values in a plain array.

So i think you need to pass an array with one value and that value replace the "?" in the statement. In this case you need a comma separated string (if you ids are int) to replace (?) in the statement.

What you do if you do not implode the values is passing an array containing an array.

You might use FIND_IN_SET(str,strlist) instead of IN () :

mysql> select id, name from customer where find_in_set(id, '10,15,20');
+----+---------+
| id | name    |
+----+---------+
| 10 | ten     |
| 15 | fifteen |
| 20 | twelve  |
+----+---------+

This way, you don't have to bind array with multiple values to IN() , you can pass list of IDs as a single comma-separated string. You can safely use PHP function implode() to generate string from array of IDs.

Though, I'm not sure if it has any impact on performance. I took a look at output of explain , and it looks like find_in_set() is not able to use indexes, so generating queries with variable number of parameters should perform better.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM