php - 条件 where 子句和 mysql 参数
php - conditional where clause and mysql parameters
我有一个表单,其中包含几个不同的字段,用于我的应用程序中的搜索功能。搜索参数可以有任意组合,可以全部填写或仅填写 1 个(或任何其他)。
截至目前,PHP 代码的相关部分如下所示(实际上有效 - 但我担心并认为这是一个非常糟糕的 design/implementation):
$whereClause = "";
if (!empty($_POST['searchAlias'])) {
$searchAlias = "%{$_POST['searchAlias']}%";
$whereClause .= " AND (users.alias LIKE ? OR users.alias LIKE ?)";
} else {
$searchAlias = "";
$whereClause .= " AND (users.alias LIKE ? OR users.alias LIKE ?)";
}
if (!empty($_POST['searchLink'])) {
$searchLink = "%{$_POST['searchLink']}%";
$whereClause .= " AND (posts.homepage LIKE ? OR posts.homepage LIKE ?)";
} else {
$searchLink = "";
$whereClause .= " AND (posts.homepage LIKE ? OR ? = '')";
}
if (!empty($_POST['searchComment'])) {
$searchComment = "%{$_POST['searchComment']}%";
$whereClause .= " AND (posts.comment LIKE ? OR posts.comment LIKE ?)";
} else {
$searchComment = "";
$whereClause .= " AND (posts.comment LIKE ? OR ? = '')";
}
if (!empty($_POST['searchCategory'])) {
$searchCategory = $_POST['searchCategory'];
$whereClause .= " AND (posts.category LIKE ? OR posts.category LIKE ?)";
} else {
$searchCategory = "";
$whereClause .= " AND (posts.category LIKE ? OR ? = '')";
}
$stmt = $connection->prepare("SELECT users.alias, posts.postId,
categories.category, posts.homepage, posts.comment, posts.timestamp,
posts.upvotes FROM ((posts INNER JOIN categories ON posts.category =
categories.id) INNER JOIN users ON posts.userId = users.userId)
WHERE 1=1 $whereClause ORDER BY postId DESC LIMIT 300");
$stmt->bind_param("ssssssss", $searchAlias,$searchAlias,
$searchLink,$searchLink, $searchComment,$searchComment,
$searchCategory,$searchCategory);
我应该补充一点,我还有 2 个日期输入字段(从和到日期),它们也可以包含在搜索中,它们没有添加到当前的 php 代码中,因为我没有还没修好。
如您所见,我确保从表单数据中设置的参数附加到 whereClause - 总是有两个 ?确保 bind_param 类型和变量可以一直保持不变。
那么,这是一个 "acceptable" 解决方案还是有什么方法可以使它变得更清晰、更简单?我已经尝试搜索不同的解决方案,但我要么搜索不够好,要么不够聪明地理解解决方案。
感谢任何帮助或想法!
亲切的问候,
埃肯
使用带有命名参数的 PDO 将使该任务更容易维护 if/when 添加了额外的搜索参数。它还可以容纳将值与多列进行比较的搜索参数,或者需要对搜索值进行类型转换。您可能需要考虑在 LIKE 条件的值前后添加“%”。这可以通过将 $_POST 值添加到数组并绑定数组值而不是 $_POST 值来完成。
编辑
我修改了我的第一个帖子以搜索匹配日期,并允许添加通配符以进行比较。还可以轻松修改代码以允许在日期之间进行两次值检查。
$postVals = array();
foreach($_POST as $varname => $varval) {
$postVals[$varname] = $varval;
}
$wherePieces = array();
$tests = array(
"searchAlias" => array("where" => "user.alias LIKE :searchAlias","addWildCard" => false),
"searchLink" => array("where" => "posts.homepage LIKE :searchLink","addWildCard" => true),
"searchComment" => array("where" => "posts.comment LIKE :searchComment","addWildCard" => true),
"searchCategory" => array("where" => "posts.category LIKE :searchCategory","addWildCard" => false),
"searchTimestamp" => array("where" => "CAST(posts.timestamp AS DATE) = CAST(:searchTimestamp AS DATE)","addWildCard" => false)
);
foreach($tests as $postname => $wherePart) {
if(isset($_POST[$postname]) && $_POST[$postname] != '') {
$wherePieces[] = $wherePart['where'];
}
}
$whereClause = "WHERE " . implode(" AND ",$wherePieces);
$qstr = "SELECT
users.alias,
posts.postId,
categories.category,
posts.homepage,
posts.comment,
posts.timestamp,
posts.upvotes
FROM posts
INNER JOIN categories
ON posts.category = categories.id
INNER JOIN users
ON posts.userId = users.userId)
$whereClause
ORDER BY postId DESC
LIMIT 300";
$stmt = $connection->prepare($qstr);
foreach($tests as $postname => $wherePart) {
if(isset($_POST[$postname]) && $_POST[$postname] != '') {
if($wherePart["addWildCard"]) {
$postVals[$postname] = '%'.$postVals[$postname].'%';
}
$stmt->bindParam(':'.$postname,$postVals[$postname]);
}
}
$stmt->execute();
注意:未测试,可能有拼写错误。
我有一个表单,其中包含几个不同的字段,用于我的应用程序中的搜索功能。搜索参数可以有任意组合,可以全部填写或仅填写 1 个(或任何其他)。
截至目前,PHP 代码的相关部分如下所示(实际上有效 - 但我担心并认为这是一个非常糟糕的 design/implementation):
$whereClause = "";
if (!empty($_POST['searchAlias'])) {
$searchAlias = "%{$_POST['searchAlias']}%";
$whereClause .= " AND (users.alias LIKE ? OR users.alias LIKE ?)";
} else {
$searchAlias = "";
$whereClause .= " AND (users.alias LIKE ? OR users.alias LIKE ?)";
}
if (!empty($_POST['searchLink'])) {
$searchLink = "%{$_POST['searchLink']}%";
$whereClause .= " AND (posts.homepage LIKE ? OR posts.homepage LIKE ?)";
} else {
$searchLink = "";
$whereClause .= " AND (posts.homepage LIKE ? OR ? = '')";
}
if (!empty($_POST['searchComment'])) {
$searchComment = "%{$_POST['searchComment']}%";
$whereClause .= " AND (posts.comment LIKE ? OR posts.comment LIKE ?)";
} else {
$searchComment = "";
$whereClause .= " AND (posts.comment LIKE ? OR ? = '')";
}
if (!empty($_POST['searchCategory'])) {
$searchCategory = $_POST['searchCategory'];
$whereClause .= " AND (posts.category LIKE ? OR posts.category LIKE ?)";
} else {
$searchCategory = "";
$whereClause .= " AND (posts.category LIKE ? OR ? = '')";
}
$stmt = $connection->prepare("SELECT users.alias, posts.postId,
categories.category, posts.homepage, posts.comment, posts.timestamp,
posts.upvotes FROM ((posts INNER JOIN categories ON posts.category =
categories.id) INNER JOIN users ON posts.userId = users.userId)
WHERE 1=1 $whereClause ORDER BY postId DESC LIMIT 300");
$stmt->bind_param("ssssssss", $searchAlias,$searchAlias,
$searchLink,$searchLink, $searchComment,$searchComment,
$searchCategory,$searchCategory);
我应该补充一点,我还有 2 个日期输入字段(从和到日期),它们也可以包含在搜索中,它们没有添加到当前的 php 代码中,因为我没有还没修好。
如您所见,我确保从表单数据中设置的参数附加到 whereClause - 总是有两个 ?确保 bind_param 类型和变量可以一直保持不变。
那么,这是一个 "acceptable" 解决方案还是有什么方法可以使它变得更清晰、更简单?我已经尝试搜索不同的解决方案,但我要么搜索不够好,要么不够聪明地理解解决方案。
感谢任何帮助或想法!
亲切的问候, 埃肯
使用带有命名参数的 PDO 将使该任务更容易维护 if/when 添加了额外的搜索参数。它还可以容纳将值与多列进行比较的搜索参数,或者需要对搜索值进行类型转换。您可能需要考虑在 LIKE 条件的值前后添加“%”。这可以通过将 $_POST 值添加到数组并绑定数组值而不是 $_POST 值来完成。
编辑
我修改了我的第一个帖子以搜索匹配日期,并允许添加通配符以进行比较。还可以轻松修改代码以允许在日期之间进行两次值检查。
$postVals = array();
foreach($_POST as $varname => $varval) {
$postVals[$varname] = $varval;
}
$wherePieces = array();
$tests = array(
"searchAlias" => array("where" => "user.alias LIKE :searchAlias","addWildCard" => false),
"searchLink" => array("where" => "posts.homepage LIKE :searchLink","addWildCard" => true),
"searchComment" => array("where" => "posts.comment LIKE :searchComment","addWildCard" => true),
"searchCategory" => array("where" => "posts.category LIKE :searchCategory","addWildCard" => false),
"searchTimestamp" => array("where" => "CAST(posts.timestamp AS DATE) = CAST(:searchTimestamp AS DATE)","addWildCard" => false)
);
foreach($tests as $postname => $wherePart) {
if(isset($_POST[$postname]) && $_POST[$postname] != '') {
$wherePieces[] = $wherePart['where'];
}
}
$whereClause = "WHERE " . implode(" AND ",$wherePieces);
$qstr = "SELECT
users.alias,
posts.postId,
categories.category,
posts.homepage,
posts.comment,
posts.timestamp,
posts.upvotes
FROM posts
INNER JOIN categories
ON posts.category = categories.id
INNER JOIN users
ON posts.userId = users.userId)
$whereClause
ORDER BY postId DESC
LIMIT 300";
$stmt = $connection->prepare($qstr);
foreach($tests as $postname => $wherePart) {
if(isset($_POST[$postname]) && $_POST[$postname] != '') {
if($wherePart["addWildCard"]) {
$postVals[$postname] = '%'.$postVals[$postname].'%';
}
$stmt->bindParam(':'.$postname,$postVals[$postname]);
}
}
$stmt->execute();
注意:未测试,可能有拼写错误。