PHP - 将PDO与IN子句数组一起使用

iRe*_*tor 60 php mysql pdo prepared-statement in-clause

我正在使用PDO执行一个带有IN子句的语句,该子句使用数组作为它的值:

$in_array = array(1, 2, 3);
$in_values = implode(',', $in_array);
$my_result = $wbdb->prepare("SELECT * FROM my_table WHERE my_value IN (".$in_values.")");
$my_result->execute();
$my_results = $my_result->fetchAll();
Run Code Online (Sandbox Code Playgroud)


上面的代码完全正常,但我的问题是为什么这不是:

 $in_array = array(1, 2, 3);
    $in_values = implode(',', $in_array);
    $my_result = $wbdb->prepare("SELECT * FROM my_table WHERE my_value IN (:in_values)");
    $my_result->execute(array(':in_values' => $in_values));
    $my_results = $my_result->fetchAll();
Run Code Online (Sandbox Code Playgroud)

此代码将返回my_value等于$in_array(1)中第一项的项,但不返回数组中的其余项(2和3).

You*_*nse 83

PDO对这些东西并不好.您需要动态创建带有问号的字符串并插入查询.

$in  = str_repeat('?,', count($in_array) - 1) . '?';
$sql = "SELECT * FROM my_table WHERE my_value IN ($in)";
$stm = $db->prepare($sql);
$stm->execute($in_array);
$data = $stm->fetchAll();
Run Code Online (Sandbox Code Playgroud)

如果查询中有其他占位符,您可以使用以下方法(代码取自我的PDO教程):

您可以使用array_merge()函数将所有变量连接到一个数组中,按照它们在查询中出现的顺序以数组的形式添加其他变量:

$arr = [1,2,3];
$in  = str_repeat('?,', count($arr) - 1) . '?';
$sql = "SELECT * FROM table WHERE foo=? AND column IN ($in) AND bar=? AND baz=?";
$stm = $db->prepare($sql);
$params = array_merge([$foo], $arr, [$bar, $baz]);
$stm->execute($params);
$data = $stm->fetchAll();
Run Code Online (Sandbox Code Playgroud)

如果您使用命名占位符,代码会稍微复杂一些,因为您必须创建一系列命名占位符,例如:id0,:id1,:id2.所以代码是:

// other parameters that are going into query
$params = ["foo" => "foo", "bar" => "bar"];

$ids = [1,2,3];
$in = "";
foreach ($ids as $i => $item)
{
    $key = ":id".$i;
    $in .= "$key,";
    $in_params[$key] = $item; // collecting values into key-value array
}
$in = rtrim($in,","); // :id0,:id1,:id2

$sql = "SELECT * FROM table WHERE foo=:foo AND id IN ($in) AND bar=:bar";
$stm = $db->prepare($sql);
$stm->execute(array_merge($params,$in_params)); // just merge two arrays
$data = $stm->fetchAll();
Run Code Online (Sandbox Code Playgroud)

幸运的是,对于命名占位符,我们不必遵循严格的顺序,因此我们可以按任何顺序合并我们的数组.

  • @RobertRocha 我认为生成占位符数组的更简洁的方法可能是`$in = implode(',', array_fill(0, count($in_array), '?'));` - 避免任何奇怪的逐一或字符串连接错误 (3认同)
  • 你能解释`count()`之后`-1`是什么意思吗? (2认同)

Gor*_*onM 13

PDO预处理语句中的变量替换不支持数组.这是一对一的.

您可以通过根据数组的长度生成所需的占位符数来解决该问题.

$variables = array ('1', '2', '3');
$placeholders = str_repeat ('?, ',  count ($variables) - 1) . '?';

$query = $pdo -> prepare ("SELECT * FROM table WHERE column IN($placeholders)");
if ($query -> execute ($variables)) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

  • @RobertRocha 因为您需要的逗号比变量少一个 (2认同)

Die*_*now 6

由于 PDO 似乎没有提供很好的解决方案,您不妨考虑使用 DBAL,它主要遵循 PDO 的 API,但也添加了一些有用的功能http://docs.doctrine-project.org/projects/doctrine-dbal/ en/latest/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion

$stmt = $conn->executeQuery('SELECT * FROM articles WHERE id IN (?)',
    array(array(1, 2, 3, 4, 5, 6)),
    array(\Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
);
Run Code Online (Sandbox Code Playgroud)

可能还有一些其他包不会增加复杂性,也不会模糊与数据库的交互(就像大多数 ORM 所做的那样),但同时使小型典型任务变得更容易。