php mysqli WHERE IN (?,?,? ...)

4
根据http://us2.php.net/manual/en/mysqli-stmt.bind-param.php,不同的类型如下:
i   corresponding variable has type integer
d   corresponding variable has type double
s   corresponding variable has type string
b   corresponding variable is a blob and will be sent in packets

然而,你如何处理这个问题:
->prepare("SELECT blabla FROM foo WHERE id IN (?)")

“?”位置应该填写一串id列表。这里可以有一个或多个项目:

$ids = "3,4,78";
->bind_param('s',$ids);

这是否可能?

我想使用预处理语句,因为它将在循环中执行。


请参见https://dev59.com/NnRC5IYBdhLWcg3wVvnL。 - beldaz
4个回答

3
正确的语法应该是:
->prepare("SELECT blabla FROM foo WHERE id IN (?, ?, ?)")

例如,对于该数组中的3个项目。然后您需要使用bind_param()分别绑定每个项目。

如果您没有关于数组大小的保证,则必须编写几个帮助函数来生成带有适当数量的“?”和绑定语句的SQL。


2
事实上,我事先不知道大小。如果我为循环的每次迭代重新编写预处理语句(以更改?的数量),那么这将打败准备好的语句的目的。 - Nathan H
我不太确定您在循环中想要实现什么。绑定到语句的值每次是否会改变?绑定的值的数量是否会改变?您是否多次执行相同的语句(不知道为什么要这样做)? - Marc W
每次循环迭代时,IN(?,?,?)中的值数量会发生变化,有时可能是(1,2,3,4),或者是(1,2,3,4,5,6,7,8,9)... - Nathan H
@nute。这可能会稍微降低速度优势,但它仍然具有免受恶意SQL注入攻击的安全优势。您始终可以通过为每个IN子句长度预先准备一个语句来重新获得速度优势。 - Cheekysoft

3
如果您有一个变量列表,每次调用时大小都不同,并且您想将其绑定到一个IN语句中,最简单的方法是在程序中生成SQL字符串,并使用循环绑定变量:
/**
 * @param  array  $values
 * @param  mysqli $db
 * @return mysqli_stmt
 */
function bindInValues(array $values, mysqli $db)
{
    $sql = sprintf('SELECT blabla FROM foo WHERE id IN (%s)',
        implode(', ', array_fill(0, count($values), '?'))
    );
    $stmt = $db->prepare($sql);
    foreach ($values as $value) {
        $stmt->bind_param('s', $value);
    }
    return $stmt;
}

如果你喜欢使用call_user_func_array函数,你可以使用动态方法调用,而不需要使用循环。
/**
 * @param  array  $values
 * @param  mysqli $db
 * @return mysqli_stmt
 */
function bindInValues(array $values, mysqli $db)
{
    $sql = sprintf('SELECT blabla FROM foo WHERE id IN (%s)',
        implode(', ', array_fill(0, count($values), '?'))
    );
    $stmt = $db->prepare($sql);
    array_unshift($values, implode('', array_fill(0, count($values), 's')));
    call_user_func_array(array($stmt, 'bind_param'), $values);
    return $stmt;
}

这意味着使用预处理语句不再高效,因为您需要在每次迭代中进行“准备”,而不是仅一次。 因为我打算连续多次发送该SELECT语句,每次参数数量都不同。 - Nathan H
你说得对 - 那是不可避免的后果... 但是没有其他办法。 - Stefan Gehrig
如果您每次发送不同的查询(与SQL结构相关而非值),则可以跳过准备步骤,直接构建包括“IN”值的SQL。 - Stefan Gehrig

-1

这样做怎么样:

$sql = sprintf("SELECT blabla FROM foo WHERE id IN(%s) ", $ids);
$stmt = $mysqli->prepare($sql);
if (!$stmt) {
    $this->throwException();
}

if (!$stmt->execute()) {
    $this->throwException();
}

如果不好的话,请告诉我为什么,这样我才能从错误中学习。谢谢!

有人可以解释一下为什么是-1吗? - kitimenpolku
我认为这可能与此答案中的评论相同,https://dev59.com/gknSa4cB1Zd3GeqPQLKN#1534520 - Brad Moore

-4

我想我找到了我的问题的答案:

->prepare("SELECT stuff FROM table_name WHERE id IN (?)");

$itemList = implode(',',$items);
$children->bind_param('s',$itemList);

使用逗号分隔的字符串时似乎工作正常。 我仍在检查结果是否真正准确...


3
嗯,那不应该起作用。在这种情况下,预处理语句应该是SELECT stuff FROM table_name WHERE id IN ('1, 2, 3, 4, 5'),但这不会按照您的期望工作... - ceejayoz
然而,到目前为止它似乎运行良好... 如果你有更好的想法,请告诉我! - Nathan H

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接