在MySQL查询的LIMIT子句中使用占位符时,PHP PDO错误


PHP PDO error when using placeholders in the LIMIT clause of a MySQL query

$sql = "SELECT sql_calc_found_rows * FROM members".
       " ORDER BY username LIMIT :startRow, :numRows";
try {
    $st = $conn->prepare($sql);
    $st->bindParam(":startRow", $startRow, PDO::PARAM_INT);
    $st->bindParam(":numRows", $numRows, PDO::PARAM_INT);
    $st->execute();
} catch (PDOException $e) {
    die("Query failed: " . $e->getMessage());
}

这里我得到了错误:

Query failed: SQLSTATE[42000]: Syntax error or access violation: 1064 SQL语法错误;查看与MySQL服务器版本对应的手册,了解在第1行"5"附近使用的正确语法。

LIMIT :startRow, :numRows:numRows中出现问题。

我试过$st->bindParam$st->bindValue,都没有工作。

我认为问题出在TBL_MEMBERS上我想这是一个视图(子选择)。例如,如果你有一个product表,你想执行下面的语句:

select sql_calc_found_rows * from select id, code, name, slug, info from products order by code

您将收到以下错误:

SQL Error(1064):你的SQL语法有错误;查看对应MySQL服务器版本的手册,在第1行"select id, code, name, slug, info from products order by code"附近使用正确的语法

但是如果你把query改成:

select sql_calc_found_rows * from (select id, code, name, slug, info from products) v order by code

this will work.

总结一下,TBL_MEMBERS是一个视图,应该放在括号中并给定别名(如果我的示例别名是'v')

我建议查看SQL查询文本PDO实际生成的内容。你可以在MySQL的常规查询日志的帮助下做到这一点。

最有可能的是,$startRow和/或$numRows的形式类型是字符串,而不是整数,因此结果查询类似于LIMIT '0', '5'(语法错误)而不是LIMIT 0, 5(正确)。

问题是,即使是PDO::PARAM_INT,当参数的形式类型不是整数时(is_int返回false), PDO将其包装在引号中。因此,你必须在绑定参数之前将其转换为整数(例如使用intval):

$st->bindParam(":startRow", intval(trim($startRow)), PDO::PARAM_INT);
$st->bindParam(":numRows", intval(trim($numRows)), PDO::PARAM_INT);

我解决了。I类型转换:numRows占位符。

$numRows=(int)$numRows;
$sql = 'SELECT sql_calc_found_rows * FROM ' . 
    TBL_MEMBERS .'ORDER BY'.  $order .'LIMIT :startRow,:numRows';
    try {
        $st = $conn->prepare($sql);
        $st->bindValue(":startRow", $startRow, PDO::PARAM_INT);
        $st->bindValue(":numRows", $numRows, PDO::PARAM_INT);
        $st->execute();
    ...

它起作用了。我还注意到'应该使用而不是"