我很好奇是否有可能使用PDO将值数组绑定到占位符。这里的用例试图传递一个值数组,以便与IN()条件一起使用。

我希望能够这样做:

<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN(:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>

并让PDO绑定并引用数组中的所有值。

目前我正在做:

<?php
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
foreach($ids as &$val)
    $val=$db->quote($val); //iterate through array and quote
$in = implode(',',$ids); //create comma separated list
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN('.$in.')'
);
$stmt->execute();
?>

这当然是工作,但只是想知道是否有一个内置的解决方案,我错过了?


当前回答

使用postgres数组("{}")是一种非常简洁的方法:

$ids = array(1,4,7,9,45);
$param = "{".implode(', ',$ids)."}";
$cmd = $db->prepare("SELECT * FROM table WHERE id = ANY (?)");
$result = $cmd->execute(array($param));

其他回答

查看PDO:预定义常量,没有PDO::PARAM_ARRAY,你需要在PDOStatement->bindParam上列出

bool PDOStatement::bindParam (mixed $parameter, mixed &$variable [, int $data_type [, int $length [, mixed $driver_options]]])

所以我认为这是不可能实现的。

简单来说:

//$db = new PDO(...);
//$ids = array(...);

$qMarks = str_repeat('?,', count($ids) - 1) . '?';
$sth = $db->prepare("SELECT * FROM myTable WHERE id IN ($qMarks)");
$sth->execute($ids);

当你有其他参数时,你可以这样做:

$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
$query = 'SELECT *
            FROM table
           WHERE X = :x
             AND id IN(';
$comma = '';
for($i=0; $i<count($ids); $i++){
  $query .= $comma.':p'.$i;       // :p0, :p1, ...
  $comma = ',';
}
$query .= ')';

$stmt = $db->prepare($query);
$stmt->bindValue(':x', 123);  // some value
for($i=0; $i<count($ids); $i++){
  $stmt->bindValue(':p'.$i, $ids[$i]);
}
$stmt->execute();

因为我做了很多动态查询,所以这是我做的一个超级简单的helper函数。

public static function bindParamArray($prefix, $values, &$bindArray)
{
    $str = "";
    foreach($values as $index => $value){
        $str .= ":".$prefix.$index.",";
        $bindArray[$prefix.$index] = $value;
    }
    return rtrim($str,",");     
}

像这样使用它:

$bindString = helper::bindParamArray("id", $_GET['ids'], $bindArray);
$userConditions .= " AND users.id IN($bindString)";

返回一个字符串:id1,:id2,:id3,并更新你的$bindArray绑定,当你需要运行你的查询时。简单!

在经历了同样的问题之后,我采用了一个更简单的解决方案(尽管仍然没有PDO::PARAM_ARRAY那样优雅):

给定数组$ids = array(2,4,32):

$newparams = array();
foreach ($ids as $n => $val){ $newparams[] = ":id_$n"; }

try {
    $stmt = $conn->prepare("DELETE FROM $table WHERE ($table.id IN (" . implode(", ",$newparams). "))");
    foreach ($ids as $n => $val){
        $stmt->bindParam(":id_$n", intval($val), PDO::PARAM_INT);
    }
    $stmt->execute();

... 等等

所以如果你正在使用一个混合值数组,你将需要更多的代码来测试你的值,然后再分配类型参数:

// inside second foreach..

$valuevar = (is_float($val) ? floatval($val) : is_int($val) ? intval($val) :  is_string($val) ? strval($val) : $val );
$stmt->bindParam(":id_$n", $valuevar, (is_int($val) ? PDO::PARAM_INT :  is_string($val) ? PDO::PARAM_STR : NULL ));

但是我还没有测试过这个。