【发布时间】:2013-05-31 20:49:20
【问题描述】:
我是 PDO 的新手,目前正在开发返回搜索结果的 API 调用。如果搜索查询有 2 个可选参数,如何设置准备语句?
$app->get('/get/search', function () {
$sql = 'SELECT * FROM user WHERE name LIKE :name AND city = :city AND gender = :gender';
try {
$stmt = cnn()->prepare($sql);
$stmt->bindParam(':name', '%'.$_GET['name'].'%', PDO::PARAM_STR);
$stmt->bindParam(':city', '%'.$_GET['city'].'%', PDO::PARAM_STR);
$stmt->bindParam(':gender', $_GET['gender'], PDO::PARAM_INT);
$stmt->execute();
if($data = $stmt->fetchAll()) {
echo json_encode($data);
} else {
echo json_encode(array('error' => 'no records found');
}
} catch(PDOException $e) {
echo json_encode(array('error' => $e->getMessage()));
}
}
这里的问题是 $_GET['city'] 和 $_GET['gender'] 都是可选的。如果我尝试运行上面的代码,它将假定任何空变量也应该与列中的空值匹配;另一方面,如果我这样做:
if($_GET['gender']) $stmt->bindParam(':gender', $_GET['gender'], PDO::PARAM_INT);
...它会返回这个错误:"SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens"
那么,如果我想为可选参数保留准备好的sql语句,解决方案是什么?谢谢!
更新
这是基于接受的答案和一些 cmets(deceze 和 bill-karwin)的解决方案:
if($_GET['name']) $where[] = 'name LIKE :name';
if($_GET['city']) $where[] = 'city LIKE :city';
if(isset($_GET['gender'])) $where[] = 'gender = :gender';
if(count($where)) {
$sql = 'SELECT * FROM user WHERE '.implode(' AND ',$where);
$stmt = cnn()->prepare($sql);
$name = '%'.$_GET['name'].'%';
if($_GET['name']) $stmt->bindValue(':name', '%'.$_GET['name'].'%', PDO::PARAM_STR);
$city = '%'.$_GET['city'].'%';
if($_GET['city']) $stmt->bindParam(':city', $city, PDO::PARAM_STR);
if(isset($_GET['gender'])) $stmt->bindParam(':gender', $_GET['gender'], PDO::PARAM_BOOL);
$stmt->execute();
if($data = $stmt->fetchAll()) {
echo json_encode($data);
}
}
【问题讨论】:
-
实际上它是一个很小的 int(0 或 1)。但这不是问题。问题是性别和城市(或任何其他未来参数)在查询字符串中都应该是可选的。使用准备好的语句是否可行?
-
@LuigiSiri 我现在使用 PDO::PARAM_BOOL,因为它只能是 1 或 0。
标签: php mysql pdo prepared-statement