PHP PDO bindParam и PDOBindArray с условием MySQL IN [duplicate]

Ваш тест не имеет ничего общего с производительностью между async/await и сырыми обещаниями. Все, что я вижу, это то, что для вычисления ошибки требуется больше времени. Ожидается

. Вернуться к основному вопросу, следует использовать async/await, а не .then с необработанными обещаниями?

Имейте в виду, что async/await - это просто синтаксический сахар над сырые обещания, поэтому не должно оказывать большого влияния на общую производительность. Тем не менее, это делает ваш код более линейным, что избавляет от когнитивных накладных расходов от разработчика.

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


Некоторое недоразумение:

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

Это неверно. Быстрая проверка:

function error() {
    return new Promise(function(res, rej) {
        res(undefined()); // uh oh
    });
}

error().then(console.log, e => console.log("Uh oh!", e.stack));

показывает весь стек ошибок, включая местоположение.

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

5 ответов

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 25 August 2018 в 10:20
поделиться

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

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 25 August 2018 в 10:20
поделиться

Поскольку 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 25 August 2018 в 10:20
поделиться

Подстановка переменных в подготовленных инструкциях 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 25 August 2018 в 10:20
поделиться

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

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

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

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

0
ответ дан PCaligari 25 August 2018 в 10:20
поделиться
Другие вопросы по тегам:

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