Как выполнить запрос SQL SELECT * IN в PHP PDO? [Дубликат]

setTimeout должен принимать функцию в качестве своего первого аргумента.

Пожалуйста, обратитесь:

https://www.w3schools.com/jsref/met_win_settimeout.asp

Здесь вы передаете результат функции в качестве первого аргумента, который является undefined.

33
задан iRector 8 February 2013 в 09:18
поделиться

6 ответов

PDO не очень хорош с такими вещами. Вам нужно создать строку с вопросительными знаками динамически и вставить в запрос.

$in  = str_repeat('?,', count($in_array) - 1) . '?';
$sql = "SELECT * FROM my_table WHERE my_value IN ($in)";
$stm = $db->prepare($sql);
$stm->execute($in_array);
$data = $stm->fetchAll();

Если в запросе есть другие заполнители, вы можете использовать следующий подход (код берется из моего PDO tutorial ):

Вы можете использовать функцию array_merge(), чтобы объединить все переменные в один массив, добавив другие переменные в виде массивов в том порядке, в каком они появляются в вашем query:

$arr = [1,2,3];
$in  = str_repeat('?,', count($arr) - 1) . '?';
$sql = "SELECT * FROM table WHERE foo=? AND column IN ($in) AND bar=? AND baz=?";
$stm = $db->prepare($sql);
$params = array_merge([$foo], $arr, [$bar, $baz]);
$stm->execute($params);
$data = $stm->fetchAll();

Если вы используете именованные заполнители, код будет немного сложнее, так как вам нужно создать последовательность именных заполнителей, например :id0,:id1,:id2. Таким образом, код будет выглядеть следующим образом:

// other parameters that are going into query
$params = ["foo" => "foo", "bar" => "bar"];

$ids = [1,2,3];
$in = "";
foreach ($ids as $i => $item)
{
    $key = ":id".$i;
    $in .= "$key,";
    $in_params[$key] = $item; // collecting values into key-value array
}
$in = rtrim($in,","); // :id0,:id1,:id2

$sql = "SELECT * FROM table WHERE foo=:foo AND id IN ($in) AND bar=:bar";
$stm = $db->prepare($sql);
$stm->execute(array_merge($params,$in_params)); // just merge two arrays
$data = $stm->fetchAll();

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

45
ответ дан Your Common Sense 22 August 2018 в 12:18
поделиться
  • 1
    Спасибо, хотя я вижу, как это может вызвать некоторую путаницу, если мне понадобятся эти заполнители в другом месте моего заявления. Вы рекомендуете какие-либо библиотеки? Может быть, с функцией getAll? – iRector 8 February 2013 в 09:59
  • 2
    Конечно. У меня не было ответа на этот вопрос какое-то время, поэтому мне пришлось написать его сам. Вы можете найти ссылку в моем профиле. Не стесняйтесь задавать любые вопросы, касающиеся использования или каких-либо проблем. – Your Common Sense 8 February 2013 в 10:09
  • 3
    Ваш ответ помог мне пока, спасибо. Я не могу найти никаких ссылок в вашем профиле. Если ваше решение больше не доступно, есть ли в настоящее время интеллектуальные библиотеки, которые вы могли бы порекомендовать? – san.chez 30 July 2015 в 01:34
  • 4
    Можете ли вы объяснить, что означает -1 после count()? – Robert Rocha 8 June 2016 в 21:30
  • 5
    @YourCommonSense это лучший ответ на такую ​​общую проблему, спасибо! – datelligence 26 September 2017 в 16:23

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

function runQuery(PDO $PDO, string $sql, array $params = [])
{
    if (!count($params)) {
        return $PDO->query($sql);
    }

    foreach ($params as $key => $values) {
        if (is_array($values)) {
            // get placeholder from array, e.g. ids => [7,12,3] would be ':ids'
            $oldPlaceholder  = ':'.$key;
            $newPlaceholders = '';
            $newParams = [];
            // loop through array to create new placeholders & new named parameters
            for($i = 1; $i <= count($values); $i++) {
                // this gives us :ids1, :ids2, :ids3 etc
                $newKey = $oldPlaceholder.$i;
                $newPlaceholders .= $newKey.', ';
                // this builds an associative array of the new named parameters
                $newParams[$newKey] = $values[$i - 1];
            }
            //trim off the trailing comma and space
            $newPlaceholders = rtrim($newPlaceholders, ', ');

            // remove the old parameter
            unset($params[$key]);

            // and replace with the new ones
            $params = array_merge($params, $newParams);

            // amend the query
            $sql = str_replace($oldPlaceholder, $newPlaceholders, $sql);
        }
    }

    $statement = $PDO->prepare($sql);
    $statement->execute($params);
    return $statement;
}

Например, передавая их в:

SELECT * FROM users WHERE userId IN (:ids)

array(1) {
  ["ids"]=>
  array(3) {
    [0]=>
    int(1)
    [1]=>
    int(2)
    [2]=>
    int(3)
  }
}

Становится:

SELECT * FROM users WHERE userId IN (:ids1, :ids2, :ids3)

array(3) {
  [":ids1"]=>
  int(1)
  [":ids2"]=>
  int(2)
  [":ids3"]=>
  int(3)
}

Это не пуленепробиваемый, но, как единственный разработчик для моих потребностей, он отлично работает, пока все равно.

0
ответ дан Codemonkey 22 August 2018 в 12:18
поделиться

Поскольку PDO, похоже, не дает хорошего решения, вы можете также рассмотреть возможность использования DBAL, который в основном следует API PDO, но также добавляет некоторые полезные функции http://docs.doctrine-project.org/ project / doctrine-dbal / ru / latest / reference / data-retrieval-and-manipulation.html # list-of-parameters-conversion

$stmt = $conn->executeQuery('SELECT * FROM articles WHERE id IN (?)',
    array(array(1, 2, 3, 4, 5, 6)),
    array(\Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
);

Возможно, есть и другие пакеты там, которые не добавляют сложности и не скрывают взаимодействия с базой данных (как и большинство ORM), но в то же время облегчают небольшие типичные задачи.

1
ответ дан Dienow 22 August 2018 в 12:18
поделиться

Подстановка переменных в подготовленных инструкциях PDO не поддерживает массивы. Это один на один.

Вы можете обойти эту проблему, создав необходимое количество заполнителей на основе длины массива.

$variables = array ('1', '2', '3');
$placeholders = str_repeat ('?, ',  count ($variables) - 1) . '?';

$query = $pdo -> prepare ("SELECT * FROM table WHERE column IN($placeholders)");
if ($query -> execute ($variables)) {
    // ...
}
10
ответ дан GordonM 22 August 2018 в 12:18
поделиться
  • 1
    Почему count ($variables) - 1) . '?'; Почему не только count($variable) – Robert Rocha 8 June 2016 в 21:43
  • 2
    @RobertRocha Поскольку вам нужно меньше запятых, чем переменных – GordonM 9 June 2016 в 13:45

Как я понимаю, это потому, что PDO будет рассматривать содержимое $ in_values ​​как отдельный элемент и будет вполне соответствующим образом. PDO увидит 1,2,3 как одну строку, поэтому запрос будет выглядеть примерно как

SELECT * FROM table WHERE my_value IN ("1,2,3")

Вы может подумать, что изменение impode будет иметь кавычки и запятые, чтобы исправить это, но это не будет. PDO увидит цитаты и изменит, как она цитирует строку.

Что касается того, почему ваш запрос соответствует первому значению, у меня нет объяснений.

0
ответ дан PCaligari 22 August 2018 в 12:18
поделиться
1
ответ дан Karin 5 November 2018 в 09:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: