How do I use pdo's prepared statement for order by and limit clauses?

时光总嘲笑我的痴心妄想 提交于 2020-01-08 16:35:34

问题


I want to use a prepared statement in which the passed-in parameters are for the ORDER BY and LIMIT clauses, like so:

$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'],
     )
    );

But $stmt->fetchAll(PDO::FETCH_ASSOC); returns nothing.

Can someone point out what's the wrong thing I am doing? Can it be done? If not,what should I reference for a complete list of clauses where parameters can be used?


回答1:


After using :

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

I got the message :

Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 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

So, when you use an array for execute, it consider your inputs as string which is not a good idea for 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);



回答2:


Prepared statements allow the DBMS to generate a query plan for your query before actually executing the query for your supplied parameters. Changing the fields for ORDER BY requires a different query plan, because ordering you data in different ways can drastically affect how the DBMS might choose to get the data: for instance, certain indexes may help in one case but not in another. For this reason the ORDER BY fields should form part of the SQL string passed into the prepare() method, rather than being bound to the query prior to execute().

As for the LIMIT clause, it's not clear whether its parameters would affect the query plan, so these may be bound later, possibly depending upon your DBMS. According to this SO answer it should be allowed.




回答3:


You can't bind a parameter to specify a language keyword or a field name - it has to be replacing a literal. Therefore, your limit values I think are fine, but your order by is not. It will be best for you to manually replace sort and dir in the string. Escape them but don't use the DB tools to do so, since they aren't string literals. Basically ensure no special characters are present.




回答4:


Although this question is rather old, I think it might still be of interest. For me it worked after I

  1. used bindParam in combination with PDO::PARAM_INT like suggested before
  2. converted the variable content into an integer value by invoking intval()

The relevant part of the code then looks like this:

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

Without using intval() I also received the error Syntax error or access violation: 1064 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



来源:https://stackoverflow.com/questions/2683576/how-do-i-use-pdos-prepared-statement-for-order-by-and-limit-clauses

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!