Как использовать подготовленное заявление pdo для предложений order by и limit? - PullRequest
16 голосов
/ 21 апреля 2010

Я хочу использовать подготовленный оператор, в котором переданные параметры предназначены для предложений ORDER BY и LIMIT, например:

$sql = 'SELECT * FROM table ORDER BY :sort :dir LIMIT :start, :results';
$stmt = $dbh->prepare($sql);
$stmt->execute(array(
     'sort'  => $_GET['sort'], 
     'dir'  => $_GET['dir'], 
     'start'  => $_GET['start'],
     'results' => $_GET['results'],
     )
    );

Но $stmt->fetchAll(PDO::FETCH_ASSOC); ничего не возвращает.*

Может кто-нибудь указать, что я не так делаю?Это можно сделать?Если нет, то на что я должен ссылаться для получения полного списка предложений, где могут использоваться параметры?

Ответы [ 4 ]

20 голосов
/ 21 апреля 2010

После использования:

$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Я получил сообщение:

Неопределенное исключение 'PDOException' с сообщение 'SQLSTATE [42000]: синтаксическая ошибка или нарушение доступа: 1064 У вас есть ошибка в вашем синтаксисе SQL; проверить руководство, которое соответствует вашему MySQL версия сервера для правильного синтаксиса используйте около '' 0 ',' 10 '' в строке 1

Итак, когда вы используете массив для выполнения, он рассматривает ваши входные данные как строку, что не очень хорошая идея для LIMIT

$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT * FROM table ORDER BY :sort :dir LIMIT :start, :results";
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':start', $_GET['start'], PDO::PARAM_INT);
$stmt->bindParam(':results', $_GET['results'], PDO::PARAM_INT);
$stmt->bindParam(':sort', $_GET['sort']);
$stmt->bindParam(':dir', $_GET['dir']);
$stmt->execute();

$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($data);
5 голосов
/ 08 августа 2011

Подготовленные операторы позволяют СУБД сгенерировать план запроса для вашего запроса перед тем, как фактически выполнить запрос для предоставленных вами параметров. Изменение полей для ORDER BY требует другого плана запроса, поскольку упорядочение данных по-разному может существенно повлиять на то, как СУБД может выбрать получение данных: например, определенные индексы могут помочь в одном случае, но не в другом. По этой причине поля ORDER BY должны составлять часть строки SQL, передаваемой в метод prepare(), а не привязываться к запросу до execute().

Что касается предложения LIMIT, неясно, повлияют ли его параметры на план запроса, поэтому они могут быть связаны позже, возможно, в зависимости от вашей СУБД. Согласно этому SO-ответу оно должно быть разрешено.

3 голосов
/ 21 апреля 2010

Нельзя связать параметр, чтобы указать ключевое слово языка или имя поля - он должен заменять литерал. Таким образом, ваши предельные значения, я думаю, в порядке, но ваш заказ по нет. Лучше всего вручную заменить sort и dir в строке. Избегайте их, но не используйте для этого инструменты БД, поскольку они не являются строковыми литералами. В основном убедитесь, что специальных символов нет.

2 голосов
/ 25 августа 2014

Хотя этот вопрос довольно старый, я думаю, что он все еще может представлять интерес. Для меня это сработало после того, как я

  1. использовал bindParam в сочетании с PDO::PARAM_INT, как предлагалось ранее
  2. преобразовал содержимое переменной в целочисленное значение, вызвав intval()

Соответствующая часть кода выглядит следующим образом:

    $stmt->bindParam(':start', intval($_GET['start']), PDO::PARAM_INT);
    $stmt->bindParam(':number', intval($_GET['number']), PDO::PARAM_INT);

Без использования intval() Я также получил ошибку Синтаксическая ошибка или нарушение прав доступа: 1064 В синтаксисе SQL имеется ошибка; проверьте руководство, соответствующее вашей версии сервера MySQL, на предмет правильного синтаксиса для использования рядом с '' 0 ', 10' в строке 1

...