Мне любопытно узнать, возможно ли привязать массив значений к заполнителю с помощью 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();
?>
Что, безусловно, делает работу, но просто интересно, есть ли встроенное решение, которое мне не хватает?
Ответы:
Я думаю, что Соулмердж прав. вам придется построить строку запроса.
исправить: Дэн, ты был прав. исправил код (хотя не проверял)
редактировать: и Крис (комментарии), и кто-то не может поспорить, что цикл foreach ...
... может быть избыточным, поэтому
foreach
цикл и$stmt->execute
можно заменить просто ...(опять же, я не проверял это)
источник
$foreach
иbindValue()
не требуется - просто выполнить с массивом. Например:$stmt->execute($ids);
str_repeat('?,', count($array) - 1). '?';
Для чего-то быстрого:
источник
$input_list = substr(str_repeat(',?', count($ids)), 1);
str_repeat('?,', count($ids) - 1) . '?'
. На один вызов меньше.execute
массив идентификаторовЭто так важно использовать
IN
заявление? Попробуйте использоватьFIND_IN_SET
оп.Например, в PDO есть запрос
Тогда вам нужно всего лишь связать массив значений, набитый запятой, как этот
и это сделано.
UPD: Как некоторые люди указали в комментариях к этому ответу, есть некоторые вопросы, которые должны быть четко изложены.
FIND_IN_SET
не использует индекс в таблице, и он все еще не реализован - посмотрите эту запись в трекере ошибок MYSQL . Спасибо @BillKarwin за уведомление.implode
как вы используете символ запятой в качестве разделителя. Спасибо @VaL за примечание.В общем, если вы не сильно зависите от индексов и не используете строки с запятой для поиска, мое решение будет намного проще, проще и быстрее, чем решения, перечисленные выше.
источник
... 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"
Поскольку я делаю много динамических запросов, это очень простая вспомогательная функция, которую я сделал.
Используйте это так:
Возвращает строку,
:id1,:id2,:id3
а также обновляет ваши$bindArray
привязки, которые вам понадобятся, когда придет время выполнить ваш запрос. Легко!источник
Решение от EvilRygy не сработало для меня. В Postgres вы можете сделать еще один обходной путь:
источник
ERROR: operator does not exist: integer = text
. По крайней мере, вам нужно добавить явное приведение.Очень простой способ для postgres - использовать массив postgres ("{}"):
источник
Вот мое решение:
Обратите внимание на использование array_values. Это может исправить ключевые проблемы заказа.
Я сливал массивы идентификаторов, а затем удалял дублирующиеся элементы. У меня было что-то вроде:
И это не удалось.
источник
$original_array
Добавить элементы перед исходным массивом:array_unshift($original_array, new_unrelated_item);
Добавить элементы после исходного массива:array_push($original_array, new_unrelated_item);
Когда значения связаны, элементы new_unrelated будут размещены в правильных местах. Это позволяет смешивать элементы Array и не-массива. `Я расширил PDO, чтобы сделать что-то похожее на то, что предлагает stefs, и мне было легче в долгосрочной перспективе:
Вы можете использовать это так:
источник
:array
в запросе указан токен в строке.if (is_array($data))
один) ненужными, но делает обработку данных более точной.Глядя на PDO: предопределенные константы, нет PDO :: PARAM_ARRAY, который вам понадобится, как указано в PDOStatement-> bindParam
Поэтому я не думаю, что это достижимо.
источник
Когда у вас есть другой параметр, вы можете сделать так:
источник
Для меня более сексуальное решение - создать динамический ассоциативный массив и использовать его.
источник
Я также понимаю, что этот поток старый, но у меня возникла уникальная проблема, когда при преобразовании устаревшего драйвера mysql в драйвер PDO мне нужно было создать функцию, которая могла бы динамически создавать как обычные параметры, так и IN из одного и того же массив параметров. Поэтому я быстро построил это:
Это все еще не проверено, однако логика, кажется, там.
Надеюсь, это поможет кому-то в том же положении,
Изменить: После некоторого тестирования я узнал:
Код отредактирован до рабочей версии.
источник
Небольшое редактирование о коде Schnalle
источник
Какую базу данных вы используете? В PostgreSQL мне нравится использовать ЛЮБОЙ (массив). Итак, чтобы использовать ваш пример:
К сожалению, это довольно непереносимо.
В других базах данных вам нужно создать свою магию, как уже упоминали другие. Вы захотите поместить эту логику в класс / функцию, чтобы сделать ее многократно используемой в вашей программе. Взгляните на комментарии на
mysql_query
странице PHP.NET, чтобы узнать больше об этой теме и примеры этого сценария.источник
Пройдя через ту же проблему, я перешел к более простому решению (хотя и не так элегантно, как
PDO::PARAM_ARRAY
было бы):учитывая массив
$ids = array(2, 4, 32)
:... и так далее
Поэтому, если вы используете массив со смешанными значениями, вам потребуется больше кода для проверки ваших значений перед назначением параметра типа:
Но я не проверял это.
источник
Как я знаю, нет никакой возможности связать массив в оператор PDO.
Но существует 2 общих решения:
Используйте позиционные заполнители (?,?,?,?) Или именованные заполнители (: id1,: id2,: id3)
$ whereIn = implode (',', array_fill (0, count ($ ids), '?'));
Цитировать массив ранее
$ whereIn = array_map (array ($ db, 'quote'), $ ids);
Оба варианта хороши и безопасны. Я предпочитаю второй, потому что он короче, и я могу изменить параметры var_dump, если мне это нужно. Используя заполнители, вы должны связать значения, и в конце ваш код SQL будет таким же.
И последнее и важное для меня - избежать ошибки «количество связанных переменных не соответствует количеству токенов».
Doctrine - отличный пример использования позиционных заполнителей только потому, что он имеет внутренний контроль над входящими параметрами.
источник
Если столбец может содержать только целые числа, вы, вероятно, могли бы сделать это без заполнителей и просто вставить идентификаторы в запрос напрямую. Вам просто нужно привести все значения массива к целым числам. Нравится:
Это не должно быть уязвимо для любых SQL-инъекций.
источник
вот мое решение. Я также расширил класс PDO:
Вот пример использования вышеуказанного кода:
Дайте мне знать, что вы думаете
источник
BindArrayParam
в ассоциативный массив, так как вы, кажется, ограничиваете его целыми числами.Невозможно использовать такой массив в PDO.
Вам нужно построить строку с параметром (или использовать?) Для каждого значения, например:
:an_array_0, :an_array_1, :an_array_2, :an_array_3, :an_array_4, :an_array_5
Вот пример:
Если вы хотите продолжать использовать
bindParam
, вы можете сделать это вместо этого:Если вы хотите использовать
?
заполнители, вы можете сделать это следующим образом:Если вы не знаете,
$ids
пусто ли это, вы должны проверить его и соответствующим образом обработать этот случай (вернуть пустой массив, либо вернуть нулевой объект, либо выдать исключение, ...).источник
Я взял немного дальше, чтобы получить ответ ближе к первоначальному вопросу об использовании заполнителей для связывания параметров.
Этот ответ должен будет сделать два цикла по массиву, который будет использоваться в запросе. Но это решает проблему наличия других заполнителей столбцов для более избирательных запросов.
источник
вы сначала установили номер "?" в запросе, а затем с помощью «для» отправки параметров, как это:
источник