在查询中使用 PDO 准备好的语句和 LIMIT 时出错 [重复]

Posted

技术标签:

【中文标题】在查询中使用 PDO 准备好的语句和 LIMIT 时出错 [重复]【英文标题】:Error while using PDO prepared statements and LIMIT in query [duplicate] 【发布时间】:2012-07-29 02:55:08 【问题描述】:

我在我的应用程序中使用 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'' 附近使用的正确语法

【问题讨论】:

【参考方案1】:

我只是偶然发现了同样的问题。对我来说,使用我自己的语句类(扩展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));

你唯一需要做的就是绑定到语句的变量有正确的类型,整数。如果你有一个数字字符串,例如从$_GET 数组中,您可以执行以下操作:

if (isset($_GET['start']) && is_numeric($_GET['start'])
    && is_int($_GET['start'] + 0) 
  $start = (int) $_GET['start'];

我不知道最后一件事是否有更简单的方法,但至少对我来说效果很好。

【讨论】:

"I'm not shure if there is an easier way..."there is an accepted answer, if you didn't notice.【参考方案2】:

关于发帖LIMIT keyword on MySQL with prepared statement,下面的代码可以解决我的问题。

$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);

感谢 Álvaro G. VicarioMaerlyn

【讨论】:

【参考方案3】:

你可以这样做:

$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);

【讨论】:

Limit 需要一个整数,强制你的限制变量是一个整数解决了真正的问题(使用的变量不被识别为整数)绑定时强制它,你永远不必担心类型你的极限变量:)。所以这个答案应该已经被接受了。【参考方案4】:

这是一个known bug,已在 5.5.6 中从内存中修复。

来自文章: LIMIT 不允许在任何上下文中使用变量。 它的参数必须是整数常量。

进一步编辑:(关于此事存在争议) 用户变量是prepared statements中LIMIT子句接受的参数,prepared statements的SQL语法可以在存储过程中使用。

第三次编辑: 这个link 解释说这些应该与准备好的语句一起使用。

【讨论】:

您链接的错误涉及存储过程,而不是准备好的语句。 @Maerlyn 是的,我自己也看到了,在看到您的评论之前进行了编辑。【参考方案5】:

date 是一个保留字,你必须用back-ticks 包装它

【讨论】:

这不是问题。即使没有连字符也可以使用

以上是关于在查询中使用 PDO 准备好的语句和 LIMIT 时出错 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

PDO 准备语句限制不起作用 [重复]

带有位域的 PDO 准备好的语句

在 PHP 中到处使用准备好的语句? (PDO)

从 PDO 准备好的语句中获取查询 [重复]

MySQL上的LIMIT关键字与准备好的语句[重复]

使用准备好的语句构建 PDO 动态查询