Я использую PDO в своем приложении. Но у меня проблема, когда я работаю с подготовленными операторами в запросе, содержащем LIMIT
. В чем проблема?
коды:
$start = 0; $rows = 20; $sql = "SELECT * FROM tbl_news ORDER BY date DESC LIMIT ?, ?"; $q = $db->prepare($sql); $q->execute(array($start , $rows));
Ошибка:
проверьте руководство, соответствующее версии вашего сервера MySQL, для правильного синтаксиса для использования рядом с '' 0 ',' 20 ''
Что касается размещения ключевого слова LIMIT в MySQL с подготовленным оператором , приведенный ниже код может решить мою проблему.
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);
Спасибо Álvaro G. Vicario и Maerlyn
Это известная ошибка, которая была зафиксирована в памяти 5.5.6.
Из статьи: LIMIT не допускает переменные в любом контексте. Его аргументы должны быть целыми константами.
Дальнейшее редактирование: (Существует спор по этому вопросу) Пользовательские переменные принимают аргументы предложения LIMIT в подготовленных операторах, а синтаксис SQL для подготовленных операторов может использоваться в хранимых процедурах.
Третье редактирование: эта ссылка объясняет, что они должны работать с подготовленными операторами.
Вы можете сделать так:
$sql = SELECT * FROM tbl_news ORDER BY date DESC LIMIT :start, :rows"; $q = $db->prepare($sql); $q->bindParam(':start', $start, PDO::PARAM_INT); $q->bindParam(':rows',$rows, PDO::PARAM_INT);
Я просто наткнулся на ту же проблему. Для меня, используя мой собственный класс операторов (расширение PDOStatement
) с помощью собственного метода execute()
он исправил его.
Это класс:
class MyPDOStatement extends PDOStatement { public function execute($input_parameters = null) { if (is_array($input_parameters)) { $i = 1; foreach ($input_parameters as $p) { // default to string datatype $parameterType = PDO::PARAM_STR; // now let's see if there is something more appropriate if (is_bool($p)) { $parameterType = PDO::PARAM_BOOL; } elseif (is_null($p)) { $parameterType = PDO::PARAM_NULL; } elseif (is_int($p)) { $parameterType = PDO::PARAM_INT; } // parameters passed to execute() are input-only parameters, so use // bindValue() $this->bindValue($i, $p, $parameterType); $i++; } } return parent::execute(); } }
Чтобы сообщить PDO использовать этот класс операторов вместо стандартного, сделайте следующее:
$db = new PDO(...); $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('MyPDOStatement'));
Теперь код в вопросе будет работать:
$start = 0; $rows = 20; $sql = "SELECT * FROM tbl_news ORDER BY date DESC LIMIT ?, ?"; $q = $db->prepare($sql); $q->execute(array($start , $rows));
Единственное, что вам нужно сделать shure, это то, что переменные, связанные с оператором, имеют правильный тип integer. Если у вас есть числовая строка, например, из массива $_GET
, вы можете сделать что-то вроде этого:
if (isset($_GET['start']) && is_numeric($_GET['start']) && is_int($_GET['start'] + 0) { $start = (int) $_GET['start']; }
Я не уверен, если есть более простой способ для последнего, но, по крайней мере, это отлично работает для меня.
$sql = "SELECT * FROM tbl_news ORDER BY `date` DESC LIMIT ?, ?";
date
– это зарезервированное слово, которое вы должны обернуть с помощью back-ticks