我很好奇是否有可能使用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();
?>

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


当前回答

对我来说,更性感的解决方案是构造一个动态关联数组并使用它

// A dirty array sent by user
$dirtyArray = ['Cecile', 'Gilles', 'Andre', 'Claude'];

// we construct an associative array like this
// [ ':name_0' => 'Cecile', ... , ':name_3' => 'Claude' ]
$params = array_combine(
    array_map(
        // construct param name according to array index
        function ($v) {return ":name_{$v}";},
        // get values of users
        array_keys($dirtyArray)
    ),
    $dirtyArray
);

// construct the query like `.. WHERE name IN ( :name_1, .. , :name_3 )`
$query = "SELECT * FROM user WHERE name IN( " . implode(",", array_keys($params)) . " )";
// here we go
$stmt  = $db->prepare($query);
$stmt->execute($params);

其他回答

您使用的是什么数据库?在PostgreSQL中,我喜欢使用ANY(数组)。重复一下你的例子:

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

不幸的是,这是非常不可移植的。

在其他数据库中,您将需要像其他人提到的那样,创建自己的魔法。当然,您需要将该逻辑放入类/函数中,以使其在整个程序中可重用。看看PHP mysql_query页面上的注释。关于这个主题的更多想法和这个场景的示例。

使用IN语句有这么重要吗?尝试使用FIND_IN_SET操作。

例如,在PDO中有这样一个查询

SELECT * FROM table WHERE FIND_IN_SET(id, :array)

然后你只需要绑定一个数组的值,用逗号括起来,就像这个

$ids_string = implode(',', $array_of_smth); // WITHOUT WHITESPACES BEFORE AND AFTER THE COMMA
$stmt->bindParam('array', $ids_string);

做完了。

UPD:正如一些人在评论中指出的,有一些问题需要明确说明。

FIND_IN_SET没有在表中使用索引,而且它还没有实现——请参阅MYSQL错误跟踪器中的这条记录。感谢@BillKarwin的通知。 不能使用内部带有逗号的字符串作为数组的搜索值。这是不可能在内爆后以正确的方式解析这样的字符串,因为你使用逗号符号作为分隔符。感谢@VaL的提示。

总之,如果您不严重依赖索引,并且不使用带逗号的字符串进行搜索,那么我的解决方案将比上面列出的解决方案更容易、更简单、更快。

因为我做了很多动态查询,所以这是我做的一个超级简单的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绑定,当你需要运行你的查询时。简单!

对我来说,更性感的解决方案是构造一个动态关联数组并使用它

// A dirty array sent by user
$dirtyArray = ['Cecile', 'Gilles', 'Andre', 'Claude'];

// we construct an associative array like this
// [ ':name_0' => 'Cecile', ... , ':name_3' => 'Claude' ]
$params = array_combine(
    array_map(
        // construct param name according to array index
        function ($v) {return ":name_{$v}";},
        // get values of users
        array_keys($dirtyArray)
    ),
    $dirtyArray
);

// construct the query like `.. WHERE name IN ( :name_1, .. , :name_3 )`
$query = "SELECT * FROM user WHERE name IN( " . implode(",", array_keys($params)) . " )";
// here we go
$stmt  = $db->prepare($query);
$stmt->execute($params);

据我所知,没有任何可能将数组绑定到PDO语句中。

但有两种常见的解决方案:

使用位置占位符(?,?,?,?)或命名占位符(:id1,:id2,:id3) 在美元=内爆(',',array_fill (0, count ($ id), ' ? ')); 之前引用数组 $where = array_map(数组($db, 'quote'), $ids);

这两种选择都是好的和安全的。 我更喜欢第二个,因为它更短,如果我需要它,我可以var_dump参数。 使用占位符,您必须绑定值,最终您的SQL代码将是相同的。

$sql = "SELECT * FROM table WHERE id IN ($whereIn)";

最后一个对我来说很重要的是避免错误“绑定变量的数量与标记的数量不匹配”

它是使用位置占位符的一个很好的例子,只是因为它对传入参数有内部控制。