一个准备好的语句,`WHERE .. IN(..)`查询和排序 - 用MySQL

kol*_*pto 21 php mysql mergesort mysqli prepared-statement

想象一下,我们有一个查询:

SELECT * FROM somewhere WHERE `id` IN(1,5,18,25) ORDER BY `name`;
Run Code Online (Sandbox Code Playgroud)

以及要获取的ID数组: $ids = array(1,5,18,25)

准备好的陈述,建议准备一个陈述并多次调用:

$stmt = $mysqli->prepare('SELECT * FROM somewhere WHERE `id`=?;');
foreach ($ids as $id){
    $stmt->bind_params('i', $id);
    $stmt->exec();
    }
Run Code Online (Sandbox Code Playgroud)

但现在我必须手动对结果进行排序.我有什么好的选择吗?

sle*_*led 23

你可以这样做:

$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
Run Code Online (Sandbox Code Playgroud)

使用这个你为每个id调用bind_param,你有mysql完成的排序.

  • @Ryan Schumacher:我错过了什么吗?我没有看到通过过滤参数的视图有什么好处.它只是一个存储的SQL语句...... (3认同)

小智 6

我相信这是最简单的答案:

$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();
Run Code Online (Sandbox Code Playgroud)

这么久你的Ids数组不包含带有非法字符的键或键,它会起作用.


Fab*_* N. 5

遇到相同的问题,并且除了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();
Run Code Online (Sandbox Code Playgroud)

  • 它称为参数解包或 splat 运算符。“bind_params”函数采用可变数量的参数。`...$ids` 表示数组在函数调用的第 n 个参数中解包。 (2认同)

mic*_*usa 5

对于执行安全 mysqli 查询并将动态数量的传入值输入到 sql 字符串中的任务,准备好的语句是需要实现的专业技术。

\n

假设传入的数据有效负载是用户提供的数据——这意味着我们无法保证数据的完整性,也无法保证数据量。事实上,预期的数据数组可能为空。下面的代码片段将演示如何将 id 数组传递给准备好的语句的子句IN ()中的条件。WHERE如果数组中没有值,则准备好的语句没有任何好处,不应使用。

\n

MySQLi 结果集对象可以通过循环立即迭代foreach()。因此,没有必要进行迭代fetch调用;只需使用数组语法访问行数据。

\n

ids 数组意味着 sql 将需要整数值。调用时bind_param(),第一个参数将是重复字符的单个字符串i。对于一般用途,如果数据是字符串或者您可能有多种数据类型(例如整数、浮点数/双精度数或字符串),那么使用重复s字符而不是i字符会更简单。

\n

代码:(带有 SQL 的 PHPize.online 演示

\n
$ids = [1, 5, 18, 25];  // this could be, for example: $_GET[\'ids\']\n$count = count($ids);\n\n$sql = \'SELECT name FROM somewhere\';\n$orderBy = \'ORDER BY name\';\nif ($count) {\n    $placeholders = implode(\',\', array_fill(0, $count, \'?\'));\n    $stmt = $mysqli->prepare("$sql WHERE id IN ($placeholders) $orderBy");\n    $stmt->bind_param(str_repeat(\'i\', $count), ...$ids);\n    $stmt->execute();\n    $result = $stmt->get_result();\n} else {\n    $result = $mysqli->query("$sql $orderBy"); // a prepared statement is unnecessary\n}\nforeach ($result as $row) {\n    echo "<div>{$row[\'name\']}</div>\\n";\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我的 PHPize 演示的输出:

\n
<div>Alan</div>\n<div>Bill</div>\n<div>Chad</div>\n<div>Dave</div>\n
Run Code Online (Sandbox Code Playgroud)\n
\n

如果您出于任何原因不需要迭代结果集,那么您可以fetch_all()。这通常在立即回显或返回 json 编码的字符串(例如,作为对 ajax 调用的响应)时使用。在这种情况下,您将该foreach()块替换为:(PHPize.online Demo with SQL

\n
echo json_encode($result->fetch_all(MYSQLI_ASSOC));\n
Run Code Online (Sandbox Code Playgroud)\n

或者简单地转储多维数组:

\n
var_export($result->fetch_all(MYSQLI_ASSOC));\n
Run Code Online (Sandbox Code Playgroud)\n

我的 PHPize 演示的输出:

\n
[{"name":"Alan"},{"name":"Bill"},{"name":"Chad"},{"name":"Dave"}]\n
Run Code Online (Sandbox Code Playgroud)\n
\n

从 PHP8.1 及更高版本开始,不再需要调用,bind_param()因为该execute()方法可以以数组形式接收参数的有效负载(如 PDO)。

\n

这意味着...

\n
$stmt->bind_param(str_repeat(\'i\', $count), ...$ids);\n$stmt->execute();\n
Run Code Online (Sandbox Code Playgroud)\n

可以替换为...

\n
$stmt->execute($ids);\n
Run Code Online (Sandbox Code Playgroud)\n

这是一个完整的基本示例:(PHPize.online Demo

\n
$ids = [1, 2, 3, 4, 5];\n$stmt = $mysqli->prepare("SELECT * FROM somewhere WHERE id IN (" . rtrim(str_repeat(\'?,\', count($ids)), \',\') . ") ORDER BY id");\n$stmt->execute($ids);\nvar_export($stmt->get_result()->fetch_all(MYSQLI_ASSOC));\n
Run Code Online (Sandbox Code Playgroud)\n

专题资源:

\n\n