ThinkPHP 提供流暢的查詢構建器,支援字串、陣列、對象三種條件格式,以及關聯查詢、區間查詢、組合查詢、複合查詢等進階功能。本文系統整理各類查詢寫法,附帶實戰 SQL 對照與最佳實踐。
$user = M('User');
$list = $user->where('id > 5 AND id < 9')->select();
// SQL: SELECT * FROM think_user WHERE id > 5 AND id < 9
$map['username'] = 'john';
$map['status'] = 1;
$list = $user->where($map)->select();
// SQL: SELECT * FROM think_user WHERE username = 'john' AND status = 1
$cond = new stdClass();
$cond->username = 'john';
$list = $user->where($cond)->select();
$map['id'] = ['gt', 20]; // id > 20
$map['id'] = ['between', '10,20']; // 10 <= id <= 20
$map['id'] = [['gt', 20], ['lt', 30], 'and']; // 20 < id < 30
$map['id'] = [['gt', 20], ['lt', 30], 'or']; // id > 20 OR id < 30
$map['username'] = 'john';
$map['password'] = ['eq', 'secret'];
$map['id'] = ['lt', 30];
$map['_logic'] = 'or'; // 所有上層條件 OR 關係
// WHERE username='john' OR password='secret' OR id<30
$where['username'] = ['eq', 'john'];
$where['password'] = ['like', 'p%'];
$where['_logic'] = 'or';
$map['_complex'] = $where; // 子查詢群組
$map['id'] = ['lt', 30]; // 主條件 AND 子群組
// WHERE id < 30 AND (username='john' OR password LIKE 'p%')
$shops = M('Shops');
$list = $shops
->join('LEFT JOIN __PRODUCT__ AS p ON shops.product_id = p.id')
->field('p.id, p.name, shops.amount, shops.product_id')
->where("shops.user_id = {$_SESSION['user_id']}")
->group('shops.id')
->select();
$list = M('Shops')
->join('LEFT JOIN __PRODUCT__ p ON shops.product_id = p.id
LEFT JOIN __PRODUCT_IMAGE__ pi ON pi.product_id = p.id')
->field('pi.url, p.id, p.name, shops.amount, shops.product_id,
p.color, p.price, shops.amount * p.price AS total')
->where("shops.user_id = {$_SESSION['user_id']}")
->group('shops.id')
->select();
技巧:使用 __TABLE__ 佔位符自動替換表前綴,避免硬編碼。
| 場景 | 推薦寫法 | 理由 |
|---|---|---|
| 簡單等值/比較 | 陣列 where(['col' => $val]) | 自動參數化、防注入、可讀 |
| 複雜邏輯 (OR/AND 混合) | 組合/複合查詢陣列 | 結構化表達邏輯,避免字串拼接 |
| 動態條件構建 | 陣列累加 + _logic | 程式化控制,易擴展 |
| 原生 SQL 片段 | where('FIND_IN_SET(?, tags)', [$id]) | 參數化原生片段,保留安全性 |
| 子查詢 | where('id IN (SELECT user_id FROM logs)') | 必要時使用,注意效能 |
where("name='$name'") → **SQL 注入**。改用 where(['name' => $name]) 或 where('name=?', [$name])。id)需用 field() 別名或 table.column 限定。field() 僅選擇聚合或分組欄位。where(['id>' => 5]) **無效**,需用 where(['id' => ['gt', 5]])。ThinkPHP 查詢構建器核心優勢在於**陣列條件自動參數化**與**複合查詢結構化表達**。實務原則:**優先用陣列條件,複雜邏輯用組合/複合查詢,關聯查詢善用 __TABLE__ 佔位符與 field() 別名,堅決杜絕字串拼接變數**。