预编译语句中的WHERE IN子句表现出意外行为。
预编译语句中的WHERE IN子句表现出意外行为。
我正在重新编写一些PHP代码,使用PDO来访问数据库,但在使用"WHERE... IN"查询时遇到了问题。
我想根据表单上被选中的项目来从数据库中删除一些内容。列表的长度和内容会有所变化,但是以这个例子来说明,假设是这样的:
$idlist = '260,201,221,216,217,169,210,212,213';
然后查询语句如下:
$query = "DELETE from `foo` WHERE `id` IN (:idlist)"; $st = $db->prepare($query); $st->execute(array(':idlist' => $idlist));
当我这样做时,只有第一个ID被删除了。(我猜测它会抛弃逗号以及之后的内容。)
我还尝试过将$idlist
设为数组,但是那样的话什么都不会被删除。
在PDO预处理语句中,如何正确使用一个项目列表?
问题的原因是在使用PDO的预处理语句中,使用WHERE IN子句时,传递参数的方式不正确。在给定的示例中,使用了一个包含数字的数组$arr作为参数,并通过将数组的元素连接成字符串来构建IN子句。
然而,这种方法在实际应用中会导致问题。因为预处理语句中的参数必须是一个数组,而不是一个字符串。因此,代码中的$stm->execute($arr)应该改为$stm->execute([$arr]),将参数作为数组传递给execute方法。
修正后的代码如下所示:
$arr = [1,2,3]; $in = str_repeat('?,', count($arr) - 1) . '?'; $sql = "SELECT * FROM table WHERE column IN ($in)"; $stm = $db->prepare($sql); $stm->execute([$arr]); $data = $stm->fetchAll();
通过将参数传递给execute方法的正确方式,可以解决预处理语句中WHERE IN子句的问题。这样,代码就能够正确地执行查询,并将结果存储在$data变量中。
问题的原因是在使用准备好的语句的WHERE IN子句时,无法将值(数字)与控制流逻辑(逗号)混合使用,需要为每个值准备一个占位符。解决方法是使用循环绑定参数,为每个值准备一个占位符。可以使用以下代码实现:
$idlist = array('260', '201', '221', '216', '217', '169', '210', '212', '213'); $questionmarks = str_repeat("?,", count($idlist)-1) . "?"; $stmt = $dbh->prepare("DELETE FROM `foo` WHERE `id` IN ($questionmarks)"); // 循环绑定参数 foreach ($idlist as $key => $value) { $stmt->bindParam($key+1, $value); } $stmt->execute();
另外,还可以使用以下代码实现占位符的生成:
implode(',', str_split(str_repeat('?', count($idList))));
或者:
implode(',', array_fill(0, count($idList), '?'));
在使用这些方法时,需要确保数组的count大于0。另外,可以通过使用`array_values`函数来确保数组具有数值键。
解决方法还可以通过在HTML中使用复选框来实现。例如:
提交表单后,可以通过`$_POST['foos']`获取一个包含所有选中复选框值的数组。然后可以使用以下代码来生成占位符和执行查询:
$questionmarks = str_repeat("?,", count($_POST['foos'])-1) . "?"; $query = "DELETE from employee_customeraccount WHERE id IN ($questionmarks)"; $st = $db->prepare($query); $st->execute($_POST['foos']);
通过使用`$_POST['foos']`数组中的值,将每个占位符替换为相应的值,并执行查询。这样可以实现预期的功能。
问题的原因是使用了循环来执行多个删除操作,这种方法虽然可行,但是效率较低。更好的方法是将所有的删除操作合并成一个查询语句。
解决方法是使用WHERE IN子句来一次性删除多个指定的项。下面是使用WHERE IN子句的代码示例:
$idlist = array('260','201','221','216','217','169','210','212','213'); $placeholders = rtrim(str_repeat('?,', count($idlist)), ','); $stmt = $dbh->prepare("DELETE FROM `foo` WHERE `id` IN ($placeholders)"); $stmt->execute($idlist);
通过将所有的id放入一个数组中,并使用implode函数将数组转换为逗号分隔的字符串,然后将字符串作为WHERE IN子句的参数传递给查询语句,可以一次性删除多个指定的项。这种方法比使用循环执行多个删除操作更高效。