问题
I'm trying to figure out how to convert my history script from mysql_query() to PDO. I have a form with 4 input fields which you can randomly select. Which means there can be 0, 1, 2, 3, 4 fields selected depending on which info you're trying to get.
I've tried to query db like this:
$q = $db->prepare('SELECT date,
name,
action
FROM history
WHERE name = :name
AND action = :action');
$q->bindParam(':name', $Name, PDO::PARAM_STR, 20);
$q->bindParam(':action', $Action, $PDO::PARAM_STR, 20);
$q->execute();
But this doesn't work if I don't have any fields selected and want the whole history shown.
With mysql_query() I'd just do this:
mysql_query('SELECT date,
name,
action
FROM history
$Name
$Action');
Which means if there's no $Name or $Action they're simply not included in the query.
Should I just copy/paste the old query into $q = $db-query('')? But that kind of defeats the purpose of using PDO.
回答1:
You could always assign default values to the params which conform to the column names.
That way your query will in the default case end up as where column = column and when there is a value present it will be where column = value.
EDIT:
Of course, my logic was slightly flawed, since bindParam does not work that way. Instead, you should incrementally build your statement according to the params set.
/* Start with the most general case for the sql query.
* The where part always evaluates to true and will thus
* always return all rows and exists only to make appending
* further conditions easier.
*/
$q = 'SELECT date, name, action FROM history WHERE 1';
/* Prepare a params array in any way you wish. A loop might be more
* efficient if it is possible, but since in this example you have
* only 2 variables, it didn't seem necessary
*/
$params = array();
if (! empty($Name)) {
$params['name'] = $Name;
}
if (! empty($Action)) {
$params['action'] = $Action;
}
/* When the params array is populated, complete the sql statement by
* appending the param names joined with ANDs
*/
foreach ($params as $key => $value) {
$q .= sprintf(' AND `%s` = :%s', $key, $key);
}
/* When the query is complete, we can prepare it */
$stmt = $db->prepare($q);
/* Then bind the values to the prepared statement
*/
foreach ($params as $key => $value) {
// Using bindValue because bindParam binds a reference, which is
// only evaluated at the point of execute
$stmt->bindValue(':'.$key, $value);
}
/* Now we're ready to execute */
$stmt->execute();
In this example, the empty check could've been done in the loop where we complete the sql statement, but that would've given you a less general example.
This example also leaves out the type param to bindValue, but that would be easily implemented, e.g. by changing the array value to an object or array having the type as a member, or by duck typing inside the assigning loop.
The query building could in this form easily be put in a function that would work for all your database querying needs, as long as you provide it the initial (general case) query along with the params array.
来源:https://stackoverflow.com/questions/4538960/dynamic-queries-with-php-pdo