我需要将一个值数组绑定到WHERE IN(?)
子句。我该怎么做?
这有效:
$mysqli = new mysqli("localhost", "root", "root", "db");
if(!$mysqli || $mysqli->connect_errno)
{
return;
}
$query_str = "SELECT name FROM table WHERE city IN ('Nashville','Knoxville')";
$query_prepared = $mysqli->stmt_init();
if($query_prepared && $query_prepared->prepare($query_str))
{
$query_prepared->execute();
但是我无法使用这样的bind_param:
$query_str = "SELECT name FROM table WHERE city IN (?)";
$query_prepared = $mysqli->stmt_init();
if($query_prepared && $query_prepared->prepare($query_str))
{
$cities = explode(",", $_GET['cities']);
$str_get_cities = "'" . implode("', '", $get_cities) . "'"; // This equals 'Nashville','Knoxville'
$query_prepared->bind_param("s", $cities);
$query_prepared->execute();
我做错了什么?
我也尝试过call_user_func_array
,但我似乎无法获得正确的语法。
在我的文章中,Mysqli 为 IN 子句准备了具有多个值的语句:
PHP 8.2 方式. execute_query((
从 PHP 8.2 开始,您可以使用一个方便的函数 execute_query((
// INSERT example
$sql = "INSERT INTO users (email, password) VALUES (?,?)"; // sql
$mysqli->execute_query($sql,[$email, $password]); // in one go
如果您的数组长度可变,则需要动态创建占位符列表
// WHERE IN example
$array = ['Nashville','Knoxville']; // our array
$parameters = str_repeat('?,', count($array) - 1) . '?'; // placeholders
$sql = "SELECT name FROM table WHERE city IN ($parameters)"; // sql
$result = $mysqli->execute_query($sql, $array); // in one go
$data = $result->fetch_all(MYSQLI_ASSOC); // fetch the data
PHP 8.1 方式。数组到 execute(( 中
从 PHP 8.1 开始,您可以直接传递数组来执行:
// INSERT example
$sql = "INSERT INTO users (email, password) VALUES (?,?)"; // sql
$stmt = $mysqli->prepare($sql); // prepare
$stmt->execute([$email, $password]); // execute with data!
// WHERE IN example
$array = ['Nashville','Knoxville']; // our array
$parameters = str_repeat('?,', count($array) - 1) . '?'; // placeholders
$sql = "SELECT name FROM table WHERE city IN ($parameters)"; // sql
$stmt = $mysqli->prepare($sql); // prepare
$stmt->execute($array);
$result = $stmt->get_result(); // get the mysqli result
$data = $result->fetch_all(MYSQLI_ASSOC); // fetch the data
旧版本,准备/绑定/执行方式
对于早期版本,任务更加复杂。
// INSERT example
$sql = "INSERT INTO users (email, password) VALUES (?,?)"; // sql
$data = [$email, $password]; // put your data into array
$stmt = $mysqli->prepare($sql); // prepare
$stmt->bind_param(str_repeat('s', count($data)), ...$data); // bind
$stmt->execute();
虽然,就像你的情况一样,我们有任意数量的占位符,但我们将不得不添加更多的代码。
- 首先,我们需要创建一个字符串,其中包含与数组中元素数量一样多的
?
标记。为此,我们将使用str_repeat()
非常方便的功能。- 然后,必须将这个带有逗号分隔问号的字符串添加到查询中。虽然它是一个变量,但在这种情况下它是安全的,因为它只包含常量值
- 那么必须像任何其他查询一样准备此查询
- 然后我们需要创建一个字符串,其中包含要与 bind_param(( 一起使用的类型。请注意,通常没有理由对绑定变量使用不同的类型 - mysql 很乐意接受它们作为字符串。有边缘情况,但极为罕见。对于日常使用,您可以始终保持简单,并使用"s"表示所有内容。
str_repeat()
再次出手相救。- 然后我们需要将数组值绑定到语句中。不幸的是,你不能像这个
$stmt->bind_param("s", $array)
那样把它写成一个变量,bind_param()
中只允许标量变量。幸运的是,有一个参数解包运算符可以完全满足我们的需要 - 将值数组发送到函数中,就好像它是一组不同的变量一样!- 其余的像往常一样 - 执行查询,获取结果并获取数据!
所以正确的示例代码是
$array = ['Nashville','Knoxville']; // our array
$in = str_repeat('?,', count($array) - 1) . '?'; // placeholders
$sql = "SELECT name FROM table WHERE city IN ($in)"; // sql
$stmt = $mysqli->prepare($sql); // prepare
$types = str_repeat('s', count($array)); //types
$stmt->bind_param($types, ...$array); // bind array at once
$stmt->execute();
$result = $stmt->get_result(); // get the mysqli result
$data = $result->fetch_all(MYSQLI_ASSOC); // fetch the data
尽管此代码相当大,但它比本主题中迄今为止提供的任何其他合理解决方案都要小得多。
不能用一个问号绑定两个变量!
对于绑定的每个变量,都需要一个问号。
"bind_param"检查每个变量是否符合要求。之后,字符串值放在引号之间。
这将不起作用:
"SELECT name FROM table WHERE city IN (?)"; ( becomes too )
$q_prepared->bind_param("s", $cities);
"SELECT name FROM table WHERE city IN ('city1,city2,city3,city4')";
它必须是:
"SELECT name FROM table WHERE city IN (?,?,?,?)"; ( becomes too )
$q_prepared->bind_param("ssss", $city1, $city2, $city3, $city4);
"SELECT name FROM table WHERE city IN ('city1', 'city2', 'city3', 'city4')";
$query_prepared->bind_param
逐个引用字符串参数。并且变量的数量和字符串类型的长度必须与语句中的参数匹配。
$query_str = "SELECT name FROM table WHERE city IN ('Nashville','Knoxville')";
将成为
$query_str = "SELECT name FROM table WHERE city IN (?,?)";
现在bind_param
必须是
bind_param("ss", $arg1, $arg2)
有了这个
$query_str = "SELECT name FROM table WHERE city IN (?)";
和bind_param
bind_param("s", $cities)
你会得到:
$query_str = "SELECT name FROM table WHERE city IN ('Nashville,Knoxville')";
这就是数组不起作用的原因。这一事实的唯一解决方案是 call_user_func_array
.
如果初始化语句,则不需要执行以下操作:
$query_prepared = $mysqli->stmt_init();
if($query_prepared && $query_prepared->prepare($query_str)) {
这是正确的:
$query_prepared = $mysqli->stmt_init();
if($query_prepared->prepare($query_str)) {
如果您不想使用 call_user_func_array
并且只有少量参数,则可以使用以下代码执行此操作。
[...]
$cities = explode(",", $_GET['cities']);
if (count($cities) > 3) { echo "too many arguments"; }
else
{
$count = count($cities);
$SetIn = "(";
for($i = 0; $i < $count; ++$i)
{
$code .= 's';
if ($i>0) {$SetIn.=",?";} else {$SetIn.="?";}
}
$SetIn .= ")";
$query_str = "SELECT name FROM table WHERE city IN " . $SetIn;
// With two arguments, $query_str will look like
// SELECT name FROM table WHERE city IN (?,?)
$query_prepared = $mysqli->stmt_init();
if($query_prepared->prepare($query_str))
{
if ($count==1) { $query_prepared->bind_param($code, $cities[0]);}
if ($count==2) { $query_prepared->bind_param($code, $cities[0], $cities[1]);}
if ($count==3) { $query_prepared->bind_param($code, $cities[0], $cities[1], $cities[2]);
// With two arguments, $query_prepared->bind_param() will look like
// $query_prepared->bind_param("ss", $cities[0], $cities[1])
}
$query_prepared->execute();
}
[...]
}
我建议您尝试一下call_user_func_array
才能到达。
寻找nick9v
的解决方案.
mysqli_stmt::bind_param
这样使用call_user_func_array:
$stmt = $mysqli->prepare("INSERT INTO t_file_result VALUES(?,?,?,?)");
$id = '1111';
$type = 2;
$result = 1;
$path = '/root';
$param = array('siis', &$id, &$type, &$result, &$path);
call_user_func_array(array($stmt, 'bind_param'), $param);
$stmt->execute();
printf("%d row inserted. 'n", $stmt->effected_rows);
$stmt->close;
从 PHP 版本 8.1 开始,不再需要绑定。与 5.0 版以来的 PDO 一样,您现在可以将参数作为数组直接传递给 execute 方法。
$mysqli = new mysqli("localhost", "root", "root", "db");
$params = ['Nashville','Knoxville'];
$placeholders = str_repeat('?,', count($params) - 1) . '?'
$query = "SELECT name FROM table WHERE city IN ($placeholders)";
$stmt = $mysqli->prepare($query);
$stmt->execute($params);
另一个示例,如果您有一个关联数组,其键与列名匹配:
$mysqli = new mysqli("localhost", "root", "root", "db");
$data = ["bar" => 23, "baz" => "some data"];
$params = array_values($data);
$placeholders = str_repeat('?,', count($params) - 1) . '?'
$columns = implode("`,`", array_keys($data));
$query = "INSERT INTO foo (`$columns`) VALUES ($placeholders)";
$stmt = $mysqli->prepare($query);
$stmt->execute($params);
另外值得一提的是,该库现在默认在发生错误时抛出异常。在版本 8.1 之前,情况并非如此。
我也遇到了这个问题,并在发现大多数人都在使用call_user_func_array之前让它与eval
一起工作:
$fields = array('model', 'title', 'price'); // Fields in WHERE clause
$values = array( // Type and value for each field
array('s', 'ABCD-1001'),
array('s', '[CD] Test Title'),
array('d', '16.00')
);
$sql = "SELECT * FROM products_info WHERE "; // Start of query
foreach ($fields as $current) { // Build where clause from fields
$sql .= '`' . $current . '` = ? AND ';
}
$sql = rtrim($sql, 'AND '); // Remove last AND
$stmt = $db->prepare($sql);
$types = ''; $vals = '';
foreach ($values as $index => $current_val) { // Build type string and parameters
$types .= $current_val[0];
$vals .= '$values[' . $index . '][1],';
}
$vals = rtrim($vals, ','); // Remove last comma
$sql_stmt = '$stmt->bind_param("' . $types . '",' . $vals . ');'; // Put bind_param line together
eval($sql_stmt); // Execute bind_param
$stmt->execute();
$stmt->bind_result($col1, $col2, $col3, $col4, $col5, $col6); // This could probably also be done dynamically in the same way
while ($stmt->fetch()) {
printf("%s %s %s %s %s %s'n", $col1, $col2, $col3, $col4, $col5, $col6);
}
php 8.2 用 execute_query 解决了所有问题
$this->execute_query($query, $parms);
喜欢
$query = "SELECT * FROM users WHERE `email` IN (?) LIMIT 1";
$parms = ["xyx@gmailx.com"];
$this->execute_query($query, $parms);
还记得 ? 是占位符和 ?(占位符(与count($parms(是相同的数字,可以通过多种方式完成。
所以在你的情况下应该是
$query = "SELECT name FROM table WHERE city IN (? , ?)";
$parms = ['Nashville','Knoxville'];
$this->execute_query($query, $parms);
https://www.php.net/manual/en/mysqli.execute-query
如果要先创建动态$query,则
$query = "SELECT name FROM table WHERE city IN (".implode(",",array_map(fn()=>"?",$parms)).")";
我这样做的方式是:准备带有所有单独问号的查询,以及类型字符串。
$cities = array('Nashville', 'Knoxville');
$dibs = '';
$query = "SELECT name FROM table WHERE city IN (";
$marks = array();
foreach ($cities as $k => $city) {
// i, s, b, d type based on the variables to bind.
$dibs .= 's';
array_push($marks, '?');
}
$query .= implode(',', $marks) . ')';
连接。
$mysql = new mysqli($host, $user, $pass, $dbname);
$statement =
$mysql->prepare($query)
OR die(sprintf(
'Query error (%s) %s', $mysql->errno, $mysql->error
))
;
然后使用"..."标记/省略号(文档(以绑定数组。
if ($statement) {
$statement->bind_param($dibs, ...$cities);
$statement->execute();
$statement->close();
}
$mysql->close();
我知道它有点违背了为了转义而绑定的目的(但至少它适用于整数列表,即 ID(。