房產、招聘、電商等領域常需「地區+類型+價格區間+面積區間+發布時間+關鍵字」多維度組合查詢。本文示範如何動態組裝 SQL WHERE 子句實現靈活查詢。
| 前端欄位 | 資料庫欄位 | 查詢邏輯 |
|---|---|---|
| 交易類型 | tradetype | 精確比對 |
| 物業類型 | wuye | 精確比對(住房/商鋪) |
| 房屋格局 | housetype | 精確比對(二房一廳等) |
| 新舊程度 | degree | 精確比對 |
| 價格 | price | 運算子 + 數值(大於/等於/小於) |
| 面積 | area | 運算子 + 數值 |
| 發布日期 | date | MySQL 日期函數(本週/月/季/半年) |
| 地址關鍵字 | address | LIKE '%keyword%' |
<?php
$conn = mysql_connect("localhost","root","");
mysql_select_db("lingyun");
$query = "SELECT * FROM message WHERE tradetype='".$tradetype."'";
$SQL = " wuye='".$wuye."'"; // 注意:原碼有變數名不一致問題
if ($housetype != "不限") $query .= " AND housetype='".$housetype."'";
if ($degree != "不限") $query .= " AND degree='".$degree."'";
if ($wuye != "不限") $query .= " AND wuye='".$wuye."'";
if ($price2 != "") {
switch($price1) {
case "大於": $query .= " AND price > '".$price2."'"; break;
case "等於": $query .= " AND price = '".$price2."'"; break;
case "小於": $query .= " AND price < '".$price2."'"; break;
}
}
if ($area2 != "") {
switch($area1) {
case "大於": $query .= " AND area > '".$area2."'"; break;
case "等於": $query .= " AND area = '".$area2."'"; break;
case "小於": $query .= " AND area < '".$area2."'"; break;
}
}
switch($pubdate) {
case "本星期內": $query .= " AND TO_DAYS(NOW()) - TO_DAYS(date) <= 7"; break;
case "一個月內": $query .= " AND TO_DAYS(NOW()) - TO_DAYS(date) <= 30"; break;
case "三個月內": $query .= " AND TO_DAYS(NOW()) - TO_DAYS(date) <= 91"; break;
case "六個月內": $query .= " AND TO_DAYS(NOW()) - TO_DAYS(date) <= 183"; break;
}
if ($address != "") $query .= " AND address LIKE '%".$address."%'";
$page = $page ?: 1;
?>
<?php
$page_size = 20;
$result = mysql_query($query);
$message_count = mysql_num_rows($result); // 注意:原碼寫死 10,此處修正
$page_count = ceil($message_count / $page_size);
$offset = ($page-1) * $page_size;
$query .= " ORDER BY date DESC LIMIT $offset, $page_size";
$result = mysql_query($query);
if ($result && mysql_num_rows($result) > 0) {
while ($row = mysql_fetch_array($result)) {
echo "<tr>";
echo "<td><img src='image/home2.gif'></td>";
echo "<td>{$row['id']} {$row['tradetype']} {$row['address']} {$row['wuye']}({$row['housetype']})
<font style='font-size:9pt'>[{$row['date']}]</font></td>";
echo "<td><a href='view_d.php?code={$row['code']}' target='_blank'>詳細內容</a></td>";
echo "</tr>";
}
} else {
echo "<tr><td>沒有找到滿足條件的記錄</td></tr>";
}
// 分頁導航
$prev = $page-1; $next = $page+1;
echo "<div align='center'>第 {$page}/{$page_count} 頁 ";
echo $page<=1 ? "|第一頁|" : "|<a href='?page=1'>第一頁</a>|";
echo $prev<1 ? "|上一頁|" : "|<a href='?page=$prev'>上一頁</a>|";
echo $next>$page_count ? "|下一頁|" : "|<a href='?page=$next'>下一頁</a>|";
echo $page>=$page_count ? "|最後一頁|" : "|<a href='?page=$page_count'>最後一頁</a>|";
echo "</div>";
?>
| 問題 | 影響 | 修正 |
|---|---|---|
$SQL 變數未使用 | 邏輯混淆 | 移除或整合至 $query |
$message_count=10 寫死 | 分頁錯誤 | 改用 mysql_num_rows($result) 或獨立 COUNT 查詢 |
| 直接拼接變數 | SQL Injection | Prepared Statements + 白名單驗證運算子 |
mysql_* 已棄用 | PHP 7+ 不支援 | 遷移至 PDO/mysqli |
| 無索引建議 | 大資料量查詢慢 | 為常用篩選欄位建立複合索引 |
// 使用 Query Builder 概念
$conditions = [];
$params = [];
if ($housetype !== '不限') {
$conditions[] = 'housetype = ?';
$params[] = $housetype;
}
if ($price2 !== '' && in_array($price1, ['大於','等於','小於'])) {
$op = ['大於'=>'>','等於'=>'=','小於'=>'<'][$price1];
$conditions[] = "price $op ?";
$params[] = $price2;
}
// ... 其他條件
$where = $conditions ? 'WHERE ' . implode(' AND ', $conditions) : '';
$sql = "SELECT * FROM message $where ORDER BY date DESC LIMIT ?, ?";
$params[] = $offset;
$params[] = $page_size;
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$rows = $stmt->fetchAll();
多條件動態查詢的核心在於「條件收集 → 運算子白名單 → 參數綁定 → 組裝 SQL」。掌握此模式,配合現代 Query Builder 或 ORM,即可構建安全、高效、可維護的複雜搜尋功能。