我可以将数组绑定到in()条件吗?

piwo6bdm  于 2021-06-23  发布在  Mysql
关注(0)|答案(21)|浏览(645)

我很想知道是否可以使用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();
?>

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

5gfr0r5j

5gfr0r5j16#

查看pdo:predefined常量没有pdo::param\u数组,正如pdostatement->bindparam中列出的那样
bool pdostatement::bindparam(mixed$参数,mixed&$variable[,int$数据类型[,int$长度[,mixed$驱动程序选项]])
所以我认为这是不可能实现的。

qnakjoqk

qnakjoqk17#

我也意识到这个线程是旧的,但我有一个独特的问题,在转换即将被弃用的mysql驱动程序到pdo驱动程序时,我不得不做一个函数,可以动态地从同一个param数组构建普通参数和ins。所以我很快就做了这个:

/**
 * mysql::pdo_query('SELECT * FROM TBL_WHOOP WHERE type_of_whoop IN :param AND siz_of_whoop = :size', array(':param' => array(1,2,3), ':size' => 3))
 *
 * @param $query
 * @param $params
 */
function pdo_query($query, $params = array()){

    if(!$query)
        trigger_error('Could not query nothing');

    // Lets get our IN fields first
    $in_fields = array();
    foreach($params as $field => $value){
        if(is_array($value)){
            for($i=0,$size=sizeof($value);$i<$size;$i++)
                $in_array[] = $field.$i;

            $query = str_replace($field, "(".implode(',', $in_array).")", $query); // Lets replace the position in the query string with the full version
            $in_fields[$field] = $value; // Lets add this field to an array for use later
            unset($params[$field]); // Lets unset so we don't bind the param later down the line
        }
    }

    $query_obj = $this->pdo_link->prepare($query);
    $query_obj->setFetchMode(PDO::FETCH_ASSOC);

    // Now lets bind normal params.
    foreach($params as $field => $value) $query_obj->bindValue($field, $value);

    // Now lets bind the IN params
    foreach($in_fields as $field => $value){
        for($i=0,$size=sizeof($value);$i<$size;$i++)
            $query_obj->bindValue($field.$i, $value[$i]); // Both the named param index and this index are based off the array index which has not changed...hopefully
    }

    $query_obj->execute();

    if($query_obj->rowCount() <= 0)
        return null;

    return $query_obj;
}

它仍然未经测试,但逻辑似乎存在。
希望它能帮助同一职位的人,
编辑:经过测试我发现:
pdo不喜欢他们名字里的“.”(如果你问我这有点愚蠢)
bindparam是错误的函数,bindvalue是正确的函数。
代码已编辑为工作版本。

w6lpcovy

w6lpcovy18#

关于施奈尔密码的一点编辑

<?php
$ids     = array(1, 2, 3, 7, 8, 9);
$inQuery = implode(',', array_fill(0, count($ids)-1, '?'));

$db   = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN(' . $inQuery . ')'
);

foreach ($ids as $k => $id)
    $stmt->bindValue(($k+1), $id);

$stmt->execute();
?>

//implode(',', array_fill(0, count($ids)-1), '?')); 
//'?' this should be inside the array_fill
//$stmt->bindValue(($k+1), $in); 
// instead of $in, it should be $id
3npbholx

3npbholx19#

据我所知,不可能将数组绑定到pdo语句中。
但存在两种常见的解决方案:
使用位置占位符(?,?,?)或命名占位符(:id1,:id2,:id3)
$where=内爆(',',数组填充(0,count($ids),'?');
引用前面的数组
$where=array\u map(数组($db,'quote'),$ids);
两种选择都是好的和安全的。我更喜欢第二个,因为它比较短,如果需要,我可以转储参数。使用占位符,您必须绑定值,最终您的sql代码将是相同的。

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

最后一个对我来说很重要的问题是避免错误“绑定变量的数量与令牌的数量不匹配”
这是使用位置占位符的一个很好的例子,只是因为它对传入的参数有内部控制。

yh2wf1be

yh2wf1be20#

我扩展了pdo,做了一些类似于stefs建议的事情,从长远来看对我来说更容易:

class Array_Capable_PDO extends PDO {
    /**
     * Both prepare a statement and bind array values to it
     * @param string $statement mysql query with colon-prefixed tokens
     * @param array $arrays associatve array with string tokens as keys and integer-indexed data arrays as values 
     * @param array $driver_options see php documention
     * @return PDOStatement with given array values already bound 
     */
    public function prepare_with_arrays($statement, array $arrays, $driver_options = array()) {

        $replace_strings = array();
        $x = 0;
        foreach($arrays as $token => $data) {
            // just for testing...
            //// tokens should be legit
            //assert('is_string($token)');
            //assert('$token !== ""');
            //// a given token shouldn't appear more than once in the query
            //assert('substr_count($statement, $token) === 1');
            //// there should be an array of values for each token
            //assert('is_array($data)');
            //// empty data arrays aren't okay, they're a SQL syntax error
            //assert('count($data) > 0');

            // replace array tokens with a list of value tokens
            $replace_string_pieces = array();
            foreach($data as $y => $value) {
                //// the data arrays have to be integer-indexed
                //assert('is_int($y)');
                $replace_string_pieces[] = ":{$x}_{$y}";
            }
            $replace_strings[] = '('.implode(', ', $replace_string_pieces).')';
            $x++;
        }
        $statement = str_replace(array_keys($arrays), $replace_strings, $statement);
        $prepared_statement = $this->prepare($statement, $driver_options);

        // bind values to the value tokens
        $x = 0;
        foreach($arrays as $token => $data) {
            foreach($data as $y => $value) {
                $prepared_statement->bindValue(":{$x}_{$y}", $value);
            }
            $x++;
        }

        return $prepared_statement;
    }
}

你可以这样使用它:

$db_link = new Array_Capable_PDO($dsn, $username, $password);

$query = '
    SELECT     *
    FROM       test
    WHERE      field1 IN :array1
     OR        field2 IN :array2
     OR        field3 = :value
';

$pdo_query = $db_link->prepare_with_arrays(
    $query,
    array(
        ':array1' => array(1,2,3),
        ':array2' => array(7,8,9)
    )
);

$pdo_query->bindValue(':value', '10');

$pdo_query->execute();
m1m5dgzv

m1m5dgzv21#

以下是我的解决方案:

$total_items = count($array_of_items);
$question_marks = array_fill(0, $total_items, '?');
$sql = 'SELECT * FROM foo WHERE bar IN (' . implode(',', $question_marks ). ')';

$stmt = $dbh->prepare($sql);
$stmt->execute(array_values($array_of_items));

注意数组值的使用。这可以解决关键的订购问题。
我正在合并ID数组,然后删除重复项。我有点像:

$ids = array(0 => 23, 1 => 47, 3 => 17);

这是失败的。

相关问题