如何将 pdo 的准备好的语句用于 order by 和 limit 子句?

Posted

技术标签:

【中文标题】如何将 pdo 的准备好的语句用于 order by 和 limit 子句?【英文标题】:How do I use pdo's prepared statement for order by and limit clauses? 【发布时间】:2011-02-10 15:10:45 【问题描述】:

我想使用一个准备好的语句,其中传入的参数用于ORDER BYLIMIT 子句,如下所示:

$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); 什么也没返回。

有人能指出我做错了什么吗?可以做到吗?如果没有,我应该参考什么以获得可以使用参数的完整条款列表?

【问题讨论】:

不,我已经在其他地方填充了值,但它仍然无法正常工作。 据我所知,您应该只绑定值,而不是列等。 【参考方案1】:

使用后:

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

我收到了消息:

未捕获的异常“PDOException”与 消息'SQLSTATE [42000]:语法错误 或访问冲突:1064 你有一个 SQL 语法错误;检查 对应于您的 mysql 的手册 正确语法的服务器版本 在第 1 行的 ''0', '10'' 附近使用

因此,当您使用数组执行时,它会将您的输入视为字符串,这对于 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);

【讨论】:

我从来没有见过limitorder子句中不能使用参数的声明,你能提供一些链接供参考吗?是否有完整的列表可以使用参数? 好像我错了,只有表/列名不能参数化。您的问题来自您忘记了 : (':sort' => $_GET['sort']) 的数组键。 不,: 是可选的(添加: 后它仍然不返回任何内容)。如果你拉得足够多,你可以在这里看到:php.net/manual/en/pdostatement.execute.php 但是pdo说:不要在查询中直接包含用户输入,那我该怎么做呢? php.net/manual/en/pdo.prepare.php 读取编辑后的版本,不是直接使用用户输入,而是使用bindValue进行绑定。【参考方案2】:

准备好的语句允许 DBMS 在为您提供的参数实际执行查询之前为您的查询生成查询计划。更改 ORDER BY 的字段需要不同的查询计划,因为以不同的方式对数据进行排序会极大地影响 DBMS 可能选择获取数据的方式:例如,某些索引可能在一种情况下有所帮助,但在另一种情况下则无济于事。出于这个原因,ORDER BY 字段应该构成传递给prepare() 方法的SQL 字符串的一部分,而不是绑定到execute() 之前的查询。

至于LIMIT子句,不清楚它的参数是否会影响查询计划,所以这些可能会在以后绑定,可能取决于你的DBMS。根据this SO answer 应该是允许的。

【讨论】:

【参考方案3】:

您不能绑定参数来指定语言关键字或字段名称 - 它必须替换文字。因此,我认为您的限制值很好,但您的订单不是。最好手动替换字符串中的 sort 和 dir。转义它们,但不要使用数据库工具来这样做,因为它们不是字符串文字。基本保证不存在特殊字符。

【讨论】:

我用:sss :xxx 替换了:sort :dir,但还是不行。 我不是这个意思。这取决于您的 DBMS,它会出现。例如,对于 MySQL,您不能对关键字或名称使用绑定参数。 php.net 的用户也发现了:php.net/manual/en/pdo.prepare.php#71127。但是,如果您使用的是不同的 DBMS,请忽略我的回答。【参考方案4】:

虽然这个问题相当古老,但我认为它可能仍然很有趣。对我来说,它在我之后起作用了

    将 bindParam 与 PDO::PARAM_INT 结合使用,就像之前建议的那样 通过调用intval()将变量内容转换为整数值

代码的相关部分如下所示:

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

没有使用intval()我也收到了错误语法错误或访问冲突:1064你的SQL语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以在第 1 行的 ''0', 10' 附近使用正确的语法

【讨论】:

以上是关于如何将 pdo 的准备好的语句用于 order by 和 limit 子句?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用准备好的 PDO 语句设置 ORDER BY 参数?

如何使用带有 BIT(1) 列的 PDO 准备语句?

如何使用准备好的语句将表单数据插入 PDO?

PDO 准备好的语句 - 参数名称中的冒号用于啥?

PDO - 使用准备好的语句将所有 sql 数据放入 html 表中

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