Чи можу я прив’язати масив до умови 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();
?>

Що, безумовно, виконує цю роботу, але просто цікаво, чи немає вбудованого рішення, якого я відсутній?


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

виправити: дан, ви мали рацію. виправили код (не перевіряли його, хоча)

редагувати: і Кріс (коментарі), і хтосьнепокоїть, що запропонував цикл передбачення ...

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

(знову ж, я цього не перевіряв)


7
Це цікаве рішення, і хоча я вважаю за краще його переглядати ідентифікатори та називати PDO :: quota (), я думаю, що індекс '?' заповнювачі заповнюються, якщо спочатку в запиті виникають інші місця заповнення, правда?
Андру

5
так, це була б проблема. але в цьому випадку ви можете створити іменовані параметри замість?.
stefs

9
Старе питання, але, на мою думку, варто зауважити, це те, що $foreachі bindValue()не потрібно - просто виконати з масивом. Напр .:$stmt->execute($ids);
Кріс

2
Генерування заповнювачів повинно бути зроблено такstr_repeat('?,', count($array) - 1). '?';
Xeoncross

8
Тільки порада для тих, хто не знає, ви не можете змішувати іменні та безіменні параметри. Отже, якщо ви використовуєте названі параметри у своєму запиті, переключіть їх на? 'S, а потім доповніть свій зсув індексу bindValue, щоб він відповідав позиції IN? З тим, де вони відносяться до вашого іншого? парами.
Justinl

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

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


6
Це набагато краще рішення, оскільки воно не порушує правило прив’язки параметрів. Це набагато безпечніше, ніж мати вбудований sql, як пропонують деякі інші тут.
Димитър Даражанський

1
Дивовижність Елегантний. Ідеально.
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. Принаймні вам потрібно додати явне кастинг.
collimarco

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

І це було невдало.


Це було чудовим рішенням. На відміну від побудови рядка запиту, при цьому правильно використовується прив'язка. Я настійно рекомендую цей.
Лінділеад

Примітка. Використовуючи рішення, ви можете додати елементи до передньої чи задньої частини масиву, щоб ви могли включити інші прив’язки. $original_array Додавання елементів перед початковим масивом: array_unshift($original_array, new_unrelated_item); Додавання елементів після початкового масиву: array_push($original_array, new_unrelated_item); Коли значення зв'язані, нові_пов'язані елементи будуть розміщені у правильних місцях. Це дозволяє змішувати масиви та елементи без масиву. `
Лінділеад

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 Common Sense, було виправлено у редакції 4 .
user2428118

11

Дивлячись на PDO: Заздалегідь визначені константи немає PDO :: PARAM_ARRAY, який вам знадобиться, як зазначено в PDOState-> bindParam

bool PDOStatement :: bindParam (змішаний параметр $, змішаний & $ змінний [, int $ data_type [, int $ length [, змішані $ driver_options]]])

Тому я не думаю, що це досяжно.


1
Я не знаю, чи це працює. Я б здогадався, що імплодований рядок отримує цитування.
соумергер

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

Важко бути впевненим, не спробувавши це в реальному сценарії, але здається нормальним. + 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 - правильна функція.

Код відредаговано на робочій версії.


8

Трохи редагування про код Шналле

<?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 після підрахунку ($ id), щоб він працював на мене, або завжди буде відсутній один заповнювач.
Марсель Буркхард

7

Яку базу даних ви використовуєте? У 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();
?>

На жаль, це досить непортативно.

В інших базах даних вам потрібно буде скласти власну магію, як згадували інші. Ви хочете ввести цю логіку в клас / функцію, щоб зробити її багаторазовою у всій програмі. Перегляньте коментарі на 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 ));

Але я цього не перевіряв.


4

Як я знаю, немає жодної можливості прив’язати масив до оператора PDO.

Але існує 2 поширених рішення:

  1. Використовуйте позитивні заповнювачі (?,?,?,?) Або іменовані заповнювачі (: id1,: id2,: id3)

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

  2. Цитувати масив раніше

    $ whereIn = array_map (масив ($ db, 'цитата'), $ ids);

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

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

І останнє і найважливіше для мене - це уникнення помилки "кількість пов'язаних змінних не відповідає кількості лексем"

Вчення - чудовий приклад використання позиційних заповнювачів, лише тому, що він має внутрішній контроль над вхідними параметрами.


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. Що це робить саме?
Lippai Zoltan

@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порожній, ви повинні протестувати його і відповідно обробити цей випадок (повернути порожній масив або повернути Null Object або кинути виняток, ...).


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

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);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.