准备好的语句,`WHERE .. IN(..)` 查询和排序 - 使用 MySQL
Posted
技术标签:
【中文标题】准备好的语句,`WHERE .. IN(..)` 查询和排序 - 使用 MySQL【英文标题】:A prepared statement, `WHERE .. IN(..)` query and sorting — with MySQL 【发布时间】:2011-04-11 19:37:06 【问题描述】:假设我们有一个查询:
SELECT * FROM somewhere WHERE `id` IN(1,5,18,25) ORDER BY `name`;
以及要获取的 ID 数组:$ids = array(1,5,18,25)
对于准备好的语句,准备一个语句并多次调用它是adviced:
$stmt = $mysqli->prepare('SELECT * FROM somewhere WHERE `id`=?;');
foreach ($ids as $id)
$stmt->bind_params('i', $id);
$stmt->exec();
但现在我必须手动对结果进行排序。我有什么不错的选择吗?
【问题讨论】:
根据您提供的链接,我认为准备语句的原因是需要更新,它不支持在一个查询中进行多次更新。而你正在选择,所以你的第一个查询就足够了。 我确信在这种情况下准备好的陈述并不好。唯一不错的解决方案是“向上查询”并让这个 ID 数组排序在那里,而不是这里。 【参考方案1】:我将添加一个缓慢而丑陋的解决方案,它仍然对任意数量的数组项使用准备好的语句:) 3 条语句在任何情况下都是通用的,并且可以在任何地方重复使用。
CREATE TEMPORARY TABLE `ids`( `id` INT );
INSERT INTO `ids` VALUES(?);
这将插入您的 ID
SELECT `id` FROM `ids` LEFT JOIN .... ;
使用其他表中的数据对ids
列表进行排序
SELECT `id` FROM `ids`;
全部选择回来
否则,您将不得不使用IN (?,?,?,....
或手动对行进行排序。最好的办法是使用简单的 MySQL 查询,或者尝试获取已经按照您喜欢的方式排序的 ID 列表。
【讨论】:
【参考方案2】:从我这里的答案https://***.com/posts/57934798/edit复制而来
使用命名占位符
$values = array(":val1"=>"value1", ":val2"=>"value2", ":val2"=>"$value3");
$statement = 'SELECT * FROM table WHERE `column` in(:'.implode(', :',array_keys($values)).') ORDER BY `column`';
使用 ??
$values = array("value1", "value2", "$value3");
$statement = 'SELECT * FROM table WHERE `column` in('.trim(str_repeat(', ?', count($values)), ', ').') ORDER BY `column`';
【讨论】:
【参考方案3】:遇到同样的问题,除了 7 年前@sled 的答案之外,这里有一种可能,无需进行 call_user_func_array(array($stmt, 'bind_param'), $ids);
步骤,但只调用一次 bind_params:
$ids = array(1,5,18,25);
// creates a string containing ?,?,?
$bindClause = implode(',', array_fill(0, count($ids), '?'));
//create a string for the bind param just containing the right amount of iii
$bindString = str_repeat('i', count($ids));
$stmt = $mysqli->prepare('SELECT * FROM somewhere WHERE `id` IN (' . $bindClause . ') ORDER BY `name`;');
$stmt->bind_params($bindString, ...$ids);
$stmt->execute();
【讨论】:
非常聪明的代码。你的bind_params函数代码中$ids前面的三个点代表什么? 它被称为参数解包或splat运算符。bind_params
函数接受可变数量的参数。 ...$ids
表示,数组在函数调用的第 n 个参数中解包。
bind_params
将抛出错误:调用未定义的方法 mysqli_stmt: :bind_params() 使用 bind_param
代替。
您能否针对单个查询中包含多个“where in”的情况提出建议?【参考方案4】:
我相信这是最简单的答案:
$ids = [1,2,3,4,5];
$pdos = $pdo->prepare("SELECT * FROM somwhere WHERE id IN (:"
. implode(',:', array_keys($ids)) . ") ORDER BY id");
foreach ($ids as $k => $id)
$pdos->bindValue(":". $k, $id);
$pdos->execute();
$results = $pdos->fetchAll();
只要您的 Id 数组不包含键或带有非法字符的键,它就会起作用。
【讨论】:
【参考方案5】:您是否考虑过使用 JOIN 和 WHERE 子句重写您的原始查询以获得所需的 IDS 以避免需要 WHERE IN 子句?我带着同样的问题来到这里,在查看了可能的解决方案后,我意识到 INNER JOIN 是我的解决方案。
【讨论】:
这是内部逻辑:应用需要通过 id 获取 N 个用户,由外部提供。很高兴你的情况不是那么具体:)【参考方案6】:另一种方法是在结果对象上使用 php usort 函数,但这是“手动”。
看到这个: Sort Object in PHP
【讨论】:
【参考方案7】:你可以这样做:
$ids = array(1,5,18,25);
// creates a string containing ?,?,?
$clause = implode(',', array_fill(0, count($ids), '?'));
$stmt = $mysqli->prepare('SELECT * FROM somewhere WHERE `id` IN (' . $clause . ') ORDER BY `name`;');
call_user_func_array(array($stmt, 'bind_param'), $ids);
$stmt->execute();
// loop through results
使用这个你为每个 id 调用 bind_param 并且你已经通过 mysql 完成了排序。
【讨论】:
是的,但不好的是查询不能被重用,所以根本不需要准备它:) @o_O Tync:数据库访问次数越少越好。欢迎您遵守 PreparedStatement 约束,但如果您需要对同一个表运行 10/20/50/100/1000+ 个查询,它就无法扩展。 为这个语句创建一个视图不是更好吗,因为它不能被重用? @Ryan Schumacher:我错过了什么吗?我看不出视图对于传递过滤参数有什么好处。它只是一个存储的 SQL 语句... 这在 php 5.3 中是有问题的,原因是:ca.php.net/manual/en/mysqli-stmt.bind-param.php#96770【参考方案8】:不,不推荐,如果您要使用ORDER BY
子句从数据库中获取某些记录。
【讨论】:
以上是关于准备好的语句,`WHERE .. IN(..)` 查询和排序 - 使用 MySQL的主要内容,如果未能解决你的问题,请参考以下文章
MYSQLI Prepared statement update statement with where in array
设置准备好的语句参数 where NOT NULL java