2011-06-10 31 views
3

我想准备一个循环中使用的语句。当我尝试执行该语句时,我在日志中看到一个错误,提示“无效的参数编号:没有参数被绑定”。zend框架:如何编写和执行WHERE IN子句?

我的代码有什么问题?

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

编辑:

我想我可能有一个错误在我成立这解释了为什么不管我尝试失败。我看到的是:

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 

编辑:

我用错了适配器。应该是Zend_Db_Statement_Pdo :-)

感谢您的答复。

+0

Paul,用生成多个'?'(如@cwallenpoole建议)和使用'FIND_IN_SET()'(我建议)来测试性能。尽管我在回答中注意到“*我不确定它是否对性能有任何影响*”,但并不意味着“*它可能具有负面影响*”。事实上,如果MySQL缓存语句(使用'FIND_IN_SET()',你总是会有相同的语句,而多个'?'语句会有所不同),如果'FIND_IN_SET'的strlist参数()'只针对查询而不是针对每一行进行解析。 – binaryLV 2011-06-10 13:33:50

+0

对不起,我已经走了另一个解决方案,因为我更熟悉它,需要破解。不过谢谢。 – 2011-06-10 14:40:21

+0

Paul,我看了'explain'的输出,看起来'find_in_set()'不能使用索引,所以“其他解决方案”可能会更好。 – binaryLV 2011-06-10 14:46:25

回答

4

?不能被一个数组替换,它必须被一个标量替换(感谢评论指出,这并不总是意味着字符串...脑屁我的一端)。让我知道这工作得更好:

$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); 
} 
+1

“*'?'不能被数组替换,它必须被字符串替换。” - 它不必用字符串替换。 Zend文档指出它可以是任何*标量*值。 'is_scalar()'的PHP文档声明标量类型是字符串以及整数,浮点数和布尔值。 – binaryLV 2011-06-10 11:46:51

+0

@binaryLV你很对!我已经解决了这个问题。 – cwallenpoole 2011-06-10 11:52:31

+0

由于性能方面的原因,我需要使用预处理语句,但是我也许可以从答案中找到有效的实现。 – 2011-06-10 12:56:10

1

你有没有试着这样做:

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

我不是Zend_framework的专家,但是当你使用的语句,来执行方法,你必须

如果您使用位置参数,或 那些标记为 标记符号('?')的问题,请在普通数组中传递绑定 值。

所以我认为你需要传递一个数组的值,并将该值替换为“?”在声明中。在这种情况下,您需要用逗号分隔的字符串(如果您的id为int)在语句中替换(?)。

如果你不implode的值是传递一个包含数组的数组。

+0

是的,我试过把数组搞砸了。它仍然返回相同的错误信息。 – 2011-06-10 12:54:25

1

您可以使用FIND_IN_SET(str,strlist)代替IN()

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

这样,您就不必绑定多个值IN()数组,你可以通过ID列表作为单个逗号分隔的字符串。您可以安全地使用PHP函数implode()从ID数组中生成字符串。

虽然,我不确定它是否对性能有任何影响。 我看了一下explain的输出,看起来find_in_set()不能使用索引,因此生成具有可变数量参数的查询应该会更好。

+0

我对find_in_set并不熟悉,但我会解释它并查看它与WHERE IN的比较。 – 2011-06-10 14:21:22