Могу ли я связать массив с условием IN ()?

562

Мне любопытно узнать, возможно ли привязать массив значений к заполнителю с помощью 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();
?>

Что, безусловно, делает работу, но просто интересно, есть ли встроенное решение, которое мне не хватает?

Andru
источник
3
Полное руководство по привязке массива к условию IN () , включая случай, когда в запросе есть другие заполнители
Ваш здравый смысл
Вопрос был закрыт как дубликат этого вопроса . Я поменял флаг дубликата, потому что этот вопрос на 4 года старше, имеет в 4 раза больше просмотров, в 3 раза больше ответов и в 12 раз больше баллов. Это явно высшая цель.
miken32
Любой, кто смотрит на это в 2020 году: вы можете попробовать github.com/morris/dop для этого.
morris4

Ответы:

262

Я думаю, что Соулмердж прав. вам придется построить строку запроса.

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

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

// bindvalue is 1-indexed, so $k+1
foreach ($ids as $k => $id)
    $stmt->bindValue(($k+1), $id);

$stmt->execute();
?>

исправить: Дэн, ты был прав. исправил код (хотя не проверял)

редактировать: и Крис (комментарии), и кто-то не может поспорить, что цикл foreach ...

(...)
// bindvalue is 1-indexed, so $k+1
foreach ($ids as $k => $id)
    $stmt->bindValue(($k+1), $id);

$stmt->execute();

... может быть избыточным, поэтому foreachцикл и $stmt->executeможно заменить просто ...

<?php 
  (...)
  $stmt->execute($ids);
?>

(опять же, я не проверял это)

stefs
источник
7
Это интересное решение, и хотя я предпочитаю его перебирать идентификаторы и вызывать PDO :: quote (), я думаю, что индекс '?' Заполнители будут испорчены, если какие-либо другие заполнители встречаются сначала в другом месте запроса, верно?
Андру
5
да, это было бы проблемой. но в этом случае вы можете создать именованные параметры вместо?
stefs
9
Старый вопрос, но я считаю, что стоит отметить, что $foreachи bindValue()не требуется - просто выполнить с массивом. Например:$stmt->execute($ids);
Крис
2
Генерация заполнителей должна быть сделана такstr_repeat('?,', count($array) - 1). '?';
Xeoncross
8
Просто совет для тех, кто не знает, вы не можете смешивать именованные и безымянные параметры. Поэтому, если вы используете именованные параметры в своем запросе, переключите их на? И затем увеличьте смещение индекса bindValue, чтобы оно соответствовало положению IN? Где бы они ни были относительно других? Титулы.
Джастин
169

Для чего-то быстрого:

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

$qMarks = str_repeat('?,', count($ids) - 1) . '?';
$sth = $db->prepare("SELECT * FROM myTable WHERE id IN ($qMarks)");
$sth->execute($ids);
DonVaughn
источник
7
Отлично, я не думал использовать аргумент input_parameters таким образом. Для тех, чьи запросы имеют больше параметров, чем список IN, вы можете использовать array_unshift и array_push, чтобы добавить необходимые аргументы в начало и конец массива. Кроме того, я предпочитаю $input_list = substr(str_repeat(',?', count($ids)), 1);
orca
7
Вы также можете попробовать str_repeat('?,', count($ids) - 1) . '?'. На один вызов меньше.
Orca
5
@erfling, это готовое утверждение, откуда придет инъекция? Я буду более чем рад внести какие-либо исправления, если вы сможете подтвердить это некоторыми фактическими доказательствами этого.
DonVaughn
5
@erfling, да, это правильно, и привязка параметров - это именно то, что мы делаем в этом примере, отправляя executeмассив идентификаторов
DonVaughn
5
О, действительно. Как-то пропустил тот факт, что вы передавали массив. Это действительно кажется безопасным и хорошим ответом. Мои извинения.
erfling
46

Это так важно использовать 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: Как некоторые люди указали в комментариях к этому ответу, есть некоторые вопросы, которые должны быть четко изложены.

  1. FIND_IN_SETне использует индекс в таблице, и он все еще не реализован - посмотрите эту запись в трекере ошибок MYSQL . Спасибо @BillKarwin за уведомление.
  2. Вы не можете использовать строку с запятой внутри в качестве значения массива для поиска. Невозможно правильно проанализировать такую ​​строку после того, implodeкак вы используете символ запятой в качестве разделителя. Спасибо @VaL за примечание.

В общем, если вы не сильно зависите от индексов и не используете строки с запятой для поиска, мое решение будет намного проще, проще и быстрее, чем решения, перечисленные выше.

Тим Тонконогов
источник
25
IN () может использовать индекс и считается как сканирование диапазона. FIND_IN_SET () не может использовать индекс.
Билл Карвин
1
Это точка. Я этого не знал. Но в любом случае нет никаких требований к производительности в этом вопросе. Для не очень больших таблиц это намного лучше и чище, чем отдельный класс для генерации запроса с разным количеством заполнителей.
Тим Тонконогов
11
Да, но у кого сегодня не такой большой стол? ;-)
Билл Карвин
3
Еще одна проблема с этим подходом, что, если внутри будет строка с запятой? Например ... FIND_IN_SET(description,'simple,search')будет работать, но не FIND_IN_SET(description,'first value,text, with coma inside')получится. Так что функция будет искать "first value", "text", "with coma inside" вместо желаемой"first value", "text, with coma inside"
VaL
33

Поскольку я делаю много динамических запросов, это очень простая вспомогательная функция, которую я сделал.

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привязки, которые вам понадобятся, когда придет время выполнить ваш запрос. Легко!

prograhammer
источник
6
Это гораздо лучшее решение, так как оно не нарушает правила привязки параметров. Это гораздо безопаснее, чем встроенный SQL, как предлагают некоторые другие здесь.
Димитар Даражанский
1
Awesomeness. Элегантный. Отлично.
Ricalsin
17

Решение от EvilRygy не сработало для меня. В Postgres вы можете сделать еще один обходной путь:


$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id = ANY (string_to_array(:an_array, ','))'
);
$stmt->bindParam(':an_array', implode(',', $ids));
$stmt->execute();
Сергей Галкин
источник
Это не работает ERROR: operator does not exist: integer = text. По крайней мере, вам нужно добавить явное приведение.
Коллимарко
17

Очень простой способ для postgres - использовать массив 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));
ЭСКОБАР
источник
это блокирует инъекцию sql?
Фабио Зангиролами
1
@ FábioZangirolami это PDO, так что да.
ESCOBAR
ДА, PDO! через 4 года. Ваш ответ был для меня хорошим, очень простым и эффективным. благодарю вас!!!
Фабио Зангиролами,
14

Вот мое решение:

$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));

Обратите внимание на использование array_values. Это может исправить ключевые проблемы заказа.

Я сливал массивы идентификаторов, а затем удалял дублирующиеся элементы. У меня было что-то вроде:

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

И это не удалось.

Progrock
источник
Это было отличное решение. В отличие от построения строки запроса, здесь правильно используется привязка. Я настоятельно рекомендую это.
Линдлиад
Примечание. Используя свое решение, вы можете добавлять элементы в начало или конец массива, чтобы вы могли включать другие привязки. $original_array Добавить элементы перед исходным массивом: array_unshift($original_array, new_unrelated_item); Добавить элементы после исходного массива: array_push($original_array, new_unrelated_item); Когда значения связаны, элементы new_unrelated будут размещены в правильных местах. Это позволяет смешивать элементы Array и не-массива. `
Линдлиад
12

Я расширил 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();
Крис
источник
1
Я обратился к первой части комментария Марка, но, как он указал, все еще небезопасно, если :arrayв запросе указан токен в строке.
Крис
4
Примечание для всех будущих читателей: это решение никогда не должно использоваться. Утверждения не предназначены для производственного кода
Ваш здравый смысл
1
YCS: спасибо за отзыв, заинтересованный в вашем мнении о подходе вне пригодности утверждений.
Крис
1
Идея почти такая же, но только без утверждений, более простой и понятный способ - не как исключение только для одного случая, а как общий способ построения каждого запроса. Каждый заполнитель отмечен своим типом. Это делает догадки (как if (is_array($data))один) ненужными, но делает обработку данных более точной.
Твой здравый смысл
1
Для тех, кто читает комментарии: проблема, упомянутая @Your Здравый смысл, была исправлена ​​в редакции 4 .
user2428118
11

Глядя на PDO: предопределенные константы, нет PDO :: PARAM_ARRAY, который вам понадобится, как указано в PDOStatement-> bindParam

bool PDOStatement :: bindParam (смешанный $ параметр, смешанный & $ переменная [, int $ data_type [, int $ длина [, смешанный $ driver_options]]])

Поэтому я не думаю, что это достижимо.


источник
1
Я не знаю, работает ли это. Я предполагаю, что взорванная строка заключена в кавычки.
soulmerge
2
Вы правы, кавычки экранированы, так что не сработает. Я удалил этот код.
11

Когда у вас есть другой параметр, вы можете сделать так:

$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();
Даниэль Милока - Бразилия
источник
Спасибо за отличный ответ. Это было единственное, что действительно помогло мне. Однако я увидел 1 ошибку. Переменная $ rs должна быть $ stmt
Пит
11

Для меня более сексуальное решение - создать динамический ассоциативный массив и использовать его.

// 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);
RousseauAlexandre
источник
Трудно быть уверенным, не пытаясь сделать это в реальном сценарии, но, кажется, все в порядке. + 1
Анант Сингх --- Жив, чтобы умереть
9

Я также понимаю, что этот поток старый, но у меня возникла уникальная проблема, когда при преобразовании устаревшего драйвера mysql в драйвер PDO мне нужно было создать функцию, которая могла бы динамически создавать как обычные параметры, так и IN из одного и того же массив параметров. Поэтому я быстро построил это:

/**
 * 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 - правильная функция.

Код отредактирован до рабочей версии.

Sammaye
источник
8

Небольшое редактирование о коде Schnalle

<?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
Аарон Анджело Викуна
источник
1
Я должен был удалить -1 после count ($ ids), чтобы он работал для меня, иначе всегда будет отсутствовать один заполнитель.
Марсель Буркхард
7

Какую базу данных вы используете? В PostgreSQL мне нравится использовать ЛЮБОЙ (массив). Итак, чтобы использовать ваш пример:

<?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();
?>

К сожалению, это довольно непереносимо.

В других базах данных вам нужно создать свою магию, как уже упоминали другие. Вы захотите поместить эту логику в класс / функцию, чтобы сделать ее многократно используемой в вашей программе. Взгляните на комментарии на mysql_queryстранице PHP.NET, чтобы узнать больше об этой теме и примеры этого сценария.

Райан Бэйр
источник
4

Пройдя через ту же проблему, я перешел к более простому решению (хотя и не так элегантно, как 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 ));

Но я не проверял это.

alan_mm
источник
4

Как я знаю, нет никакой возможности связать массив в оператор PDO.

Но существует 2 общих решения:

  1. Используйте позиционные заполнители (?,?,?,?) Или именованные заполнители (: id1,: id2,: id3)

    $ whereIn = implode (',', array_fill (0, count ($ ids), '?'));

  2. Цитировать массив ранее

    $ whereIn = array_map (array ($ db, 'quote'), $ ids);

Оба варианта хороши и безопасны. Я предпочитаю второй, потому что он короче, и я могу изменить параметры var_dump, если мне это нужно. Используя заполнители, вы должны связать значения, и в конце ваш код SQL будет таким же.

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

И последнее и важное для меня - избежать ошибки «количество связанных переменных не соответствует количеству токенов».

Doctrine - отличный пример использования позиционных заполнителей только потому, что он имеет внутренний контроль над входящими параметрами.

Олег Матей
источник
4

Если столбец может содержать только целые числа, вы, вероятно, могли бы сделать это без заполнителей и просто вставить идентификаторы в запрос напрямую. Вам просто нужно привести все значения массива к целым числам. Нравится:

$listOfIds = implode(',',array_map('intval', $ids));
$stmt = $db->prepare(
    "SELECT *
     FROM table
     WHERE id IN($listOfIds)"
);
$stmt->execute();

Это не должно быть уязвимо для любых SQL-инъекций.

Кодос Джонсон
источник
3

вот мое решение. Я также расширил класс PDO:

class Db extends PDO
{

    /**
     * SELECT ... WHERE fieldName IN (:paramName) workaround
     *
     * @param array  $array
     * @param string $prefix
     *
     * @return string
     */
    public function CreateArrayBindParamNames(array $array, $prefix = 'id_')
    {
        $newparams = [];
        foreach ($array as $n => $val)
        {
            $newparams[] = ":".$prefix.$n;
        }
        return implode(", ", $newparams);
    }

    /**
     * Bind every array element to the proper named parameter
     *
     * @param PDOStatement $stmt
     * @param array        $array
     * @param string       $prefix
     */
    public function BindArrayParam(PDOStatement &$stmt, array $array, $prefix = 'id_')
    {
        foreach($array as $n => $val)
        {
            $val = intval($val);
            $stmt -> bindParam(":".$prefix.$n, $val, PDO::PARAM_INT);
        }
    }
}

Вот пример использования вышеуказанного кода:

$idList = [1, 2, 3, 4];
$stmt = $this -> db -> prepare("
  SELECT
    `Name`
  FROM
    `User`
  WHERE
    (`ID` IN (".$this -> db -> CreateArrayBindParamNames($idList)."))");
$this -> db -> BindArrayParam($stmt, $idList);
$stmt -> execute();
foreach($stmt as $row)
{
    echo $row['Name'];
}

Дайте мне знать, что вы думаете

Липпай Золтан
источник
Забыл упомянуть, что это основано на ответе пользователя 2188977, ниже.
Липпай Золтан
Я не уверен, что такое getOne (), он не является частью PDO. Я видел это только в PEAR. Что именно это делает?
Липпай Золтан
@YourCommonSense вы можете опубликовать свою пользовательскую функцию в качестве ответа?
Обнуляемость
Я бы предложил передать тип данных BindArrayParamв ассоциативный массив, так как вы, кажется, ограничиваете его целыми числами.
Ян Бриндли,
2

Невозможно использовать такой массив в PDO.

Вам нужно построить строку с параметром (или использовать?) Для каждого значения, например:

:an_array_0, :an_array_1, :an_array_2, :an_array_3, :an_array_4, :an_array_5

Вот пример:

<?php
$ids = array(1,2,3,7,8,9);
$sqlAnArray = join(
    ', ',
    array_map(
        function($index) {
            return ":an_array_$index";
        },
        array_keys($ids)
    )
);
$db = new PDO(
    'mysql:dbname=mydb;host=localhost',
    'user',
    'passwd'
);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN('.$sqlAnArray.')'
);
foreach ($ids as $index => $id) {
    $stmt->bindValue("an_array_$index", $id);
}

Если вы хотите продолжать использовать bindParam, вы можете сделать это вместо этого:

foreach ($ids as $index => $id) {
    $stmt->bindParam("an_array_$index", $ids[$id]);
}

Если вы хотите использовать ?заполнители, вы можете сделать это следующим образом:

<?php
$ids = array(1,2,3,7,8,9);
$sqlAnArray = '?' . str_repeat(', ?', count($ids)-1);
$db = new PDO(
    'mysql:dbname=dbname;host=localhost',
    'user',
    'passwd'
);
$stmt = $db->prepare(
    'SELECT *
     FROM phone_number_lookup
     WHERE country_code IN('.$sqlAnArray.')'
);
$stmt->execute($ids);

Если вы не знаете, $idsпусто ли это, вы должны проверить его и соответствующим образом обработать этот случай (вернуть пустой массив, либо вернуть нулевой объект, либо выдать исключение, ...).

Педро Амарал Коуту
источник
0

Я взял немного дальше, чтобы получить ответ ближе к первоначальному вопросу об использовании заполнителей для связывания параметров.

Этот ответ должен будет сделать два цикла по массиву, который будет использоваться в запросе. Но это решает проблему наличия других заполнителей столбцов для более избирательных запросов.

//builds placeholders to insert in IN()
foreach($array as $key=>$value) {
    $in_query = $in_query . ' :val_' . $key . ', ';
}

//gets rid of trailing comma and space
$in_query = substr($in_query, 0, -2);

$stmt = $db->prepare(
    "SELECT *
     WHERE id IN($in_query)";

//pind params for your placeholders.
foreach ($array as $key=>$value) {
    $stmt->bindParam(":val_" . $key, $array[$key])
}

$stmt->execute();
Joseph_J
источник
0

вы сначала установили номер "?" в запросе, а затем с помощью «для» отправки параметров, как это:

require 'dbConnect.php';
$db=new dbConnect();
$array=[];
array_push($array,'value1');
array_push($array,'value2');
$query="SELECT * FROM sites WHERE kind IN (";

foreach ($array as $field){
    $query.="?,";
}
$query=substr($query,0,strlen($query)-1);
$query.=")";
$tbl=$db->connection->prepare($query);
for($i=1;$i<=count($array);$i++)
    $tbl->bindParam($i,$array[$i-1],PDO::PARAM_STR);
$tbl->execute();
$row=$tbl->fetchAll(PDO::FETCH_OBJ);
var_dump($row);
Али Чегини
источник