23
SELECT id, content, date
FROM comment
WHERE post = ?
ORDER BY date DESC
LIMIT ?, ?

使用 PDO(我正在使用具有 Apache 2.2.21、PHP 高达 5.3.6 和 MySQL 5.5.9 的 MAMP 2.0.5)准备好的语句,如果我用

LIMIT 0, 10

有用。

我在 MySQL 的错误中看到这是以前版本中的错误,但我不明白这是否仍有待修复。

如果这仍然是一个问题,有没有办法以另一种方式选择一系列行?

代码:

$comments = $db->prepare($query); 
/* where $db is the PDO object */ 
$comments->execute(array($post, $min, $max)); 
4

2 回答 2

49

这是问题所在:

$comments = $db->prepare($query); 
/* where $db is the PDO object */ 
$comments->execute(array($post, $min, $max));

PDOStatement::execute()的手册页说(强调我的):

参数

input_parameters一个包含与正在执行的 SQL 语句中的绑定参数一样多的元素的值数组。所有值都被视为 PDO::PARAM_STR

因此,您的参数将作为字符串插入,因此最终的 SQL 代码如下所示:

LIMIT '0', '10'

这是 MySQL 不会强制转换为数字但会触发解析错误的特殊情况:

mysql> SELECT 1 LIMIT 0, 10;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)

mysql> SELECT 1 LIMIT '0', '10';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''0', '10'' at line 1

文档必须说什么:

LIMIT子句可用于限制SELECT语句返回的行数。LIMIT接受一个或两个数字参数,它们都必须是非负整数常量,但以下情况除外:

  • 在准备好的语句中,LIMIT可以使用 ? 指定参数 占位符标记。

  • 在存储的程序中,LIMIT可以使用整数值的例程参数或局部变量来指定参数。

您的选择包括:

  • 一个个绑定参数,这样就可以设置类型了:

    $comments->bindParam(1, $post, PDO::PARAM_STR);
    $comments->bindParam(2, $min, PDO::PARAM_INT);
    $comments->bindParam(3, $min, PDO::PARAM_INT);
    
  • 不要将这些值作为参数传递:

    $query = sprintf('SELECT id, content, date
        FROM comment
        WHERE post = ?
        ORDER BY date DESC
        LIMIT %d, %d', $min, $max);
    
  • 禁用模拟准备(MySQL 驱动程序有一个错误/功能会使其引用数字参数):

    $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);
    
于 2012-04-04T15:22:47.017 回答
5

您可以声明一个特定的属性来解决问题。

$dbh->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );

另一个答案说明了它是如何工作的。默认情况下,PDO 仅模拟准备,并且当您静默绑定变量时,无需设置类型,PDO 默认将它们视为字符串。SQL 中的字符串必须被引用和转义——因此您的 LIMIT 子句中有引号和语法错误。而当使用本机准备好的语句时,数据库可以设法整理出适当的类型。

于 2012-04-04T15:23:14.770 回答