# 查詢語言
[上一頁](71.html "上一頁")[下一頁](73.html "下一頁")
ThinkPHP內置了非常靈活的查詢方法,可以快速的進行數據查詢操作,查詢條件可以用于CURD等任何操作,作為where方法的參數傳入即可,下面來一一講解查詢語言的內涵。### 查詢方式
ThinkPHP可以支持直接使用字符串作為查詢條件,但是大多數情況推薦使用索引數組或者對象來作為查詢條件,因為會更加安全。
**一、使用字符串作為查詢條件**
這是最傳統的方式,但是安全性不高,例如:`$User?=?M("User");?//?實例化User對象<br class="calibre5"></br>$User->where('type=1?AND?status=1')->select();?`最后生成的SQL語句是
SELECT * FROM think_user WHERE type=1 AND status=1**二、使用數組作為查詢條件**`$User?=?M("User");?//?實例化User對象<br class="calibre5"></br>$condition['name']?=?'thinkphp';<br class="calibre5"></br>$condition['status']?=?1;<br class="calibre5"></br>//?把查詢條件傳入查詢方法<br class="calibre5"></br>$User->where($condition)->select();?`最后生成的SQL語句是
SELECT * FROM think_user WHERE `name`='thinkphp' AND status=1
如果進行多字段查詢,那么字段之間的默認邏輯關系是 邏輯與 AND,但是用下面的規則可以更改默認的邏輯判斷,通過使用 _logic 定義查詢邏輯:`$User?=?M("User");?//?實例化User對象<br class="calibre5"></br>$condition['name']?=?'thinkphp';<br class="calibre5"></br>$condition['account']?=?'thinkphp';<br class="calibre5"></br>$condition['_logic']?=?'OR';<br class="calibre5"></br>//?把查詢條件傳入查詢方法<br class="calibre5"></br>$User->where($condition)->select();?`最后生成的SQL語句是
SELECT * FROM think_user WHERE `name`='thinkphp' OR `account`='thinkphp'**三、使用對象方式來查詢** (這里以stdClass內置對象為例)`$User?=?M("User");?//?實例化User對象<br class="calibre5"></br>//?定義查詢條件<br class="calibre5"></br>$condition?=?new?stdClass();?<br class="calibre5"></br>$condition->name?=?'thinkphp';?<br class="calibre5"></br>$condition->status=?1;?<br class="calibre5"></br>$User->where($condition)->select();?`最后生成的SQL語句和上面一樣
SELECT * FROM think_user WHERE `name`='thinkphp' AND status=1
使用對象方式查詢和使用數組查詢的效果是相同的,并且是可以互換的,大多數情況下,我們建議采用數組方式更加高效,后面我們會以數組方式為例來講解具體的查詢語言用法。### 表達式查詢
上面的查詢條件僅僅是一個簡單的相等判斷,可以使用查詢表達式支持更多的SQL查詢語法,并且可以用于數組或者對象方式的查詢(下面僅以數組方式為例說明),查詢表達式的使用格式:
$map['字段名'] = array('表達式','查詢條件');
表達式不分大小寫,支持的查詢表達式有下面幾種,分別表示的含義是:表達式 含義 EQ 等于(=) NEQ 不等于(<>) GT 大于(>) EGT 大于等于(>=) LT 小于(<) ELT 小于等于(<=) LIKE 模糊查詢 \[NOT\] BETWEEN (不在)區間查詢 \[NOT\] IN (不在)IN 查詢 EXP 表達式查詢,支持SQL語法 示例如下:
**EQ** :等于(=)
例如:`$map['id']??=?array('eq',100);`和下面的查詢等效`$map['id']??=?100;`表示的查詢條件就是 id = 100
**NEQ**: 不等于(<>)
例如:`$map['id']??=?array('neq',100);`表示的查詢條件就是 id <> 100
**GT**:大于(>)
例如:`$map['id']??=?array('gt',100);`表示的查詢條件就是 id > 100
**EGT**:大于等于(>=)
例如:`$map['id']??=?array('egt',100);`表示的查詢條件就是 id >= 100
**LT**:小于(<)
例如:`$map['id']??=?array('lt',100);`表示的查詢條件就是 id < 100
**ELT**: 小于等于(<=)
例如:`$map['id']??=?array('elt',100);`表示的查詢條件就是 id <= 100
**\[NOT\] LIKE**: 同sql的LIKE
例如:`$map['name']?=?array('like','thinkphp%');`查詢條件就變成 name like 'thinkphp%'
如果配置了DB_LIKE_FIELDS參數的話,某些字段也會自動進行模糊查詢。例如設置了:`'DB_LIKE_FIELDS'=>'title|content'`的話,使用`$map['title']?=?'thinkphp';`查詢條件就會變成 name like '%thinkphp%'
支持數組方式,例如`$map['a']?=array('like',array('%thinkphp%','%tp'),'OR');<br class="calibre5"></br>$map['b']?=array('notlike',array('%thinkphp%','%tp'),'AND');`生成的查詢條件就是:
(a like '%thinkphp%' OR a like '%tp') AND (b not like '%thinkphp%' AND b not like '%tp')
**\[NOT\] BETWEEN** :同sql的[not] between, 查詢條件支持字符串或者數組,例如:`$map['id']??=?array('between','1,8');`和下面的等效:`$map['id']??=?array('between',array('1','8'));`查詢條件就變成 id BETWEEN 1 AND 8
**\[NOT\] IN**: 同sql的[not] in ,查詢條件支持字符串或者數組,例如:`$map['id']??=?array('not?in','1,5,8');`和下面的等效:`$map['id']??=?array('not?in',array('1','5','8'));`查詢條件就變成 id NOT IN (1,5, 8)
**EXP**:表達式,支持更復雜的查詢情況
例如:`$map['id']??=?array('in','1,3,8');`可以改成:`$map['id']??=?array('exp','?IN?(1,3,8)?');`exp查詢的條件不會被當成字符串,所以后面的查詢條件可以使用任何SQL支持的語法,包括使用函數和字段名稱。查詢表達式不僅可用于查詢條件,也可以用于數據更新,例如:`$User?=?M("User");?//?實例化User對象<br class="calibre5"></br>//?要修改的數據對象屬性賦值<br class="calibre5"></br>$data['name']?=?'ThinkPHP';<br class="calibre5"></br>$data['score']?=?array('exp','score+1');//?用戶的積分加1<br class="calibre5"></br>$User->where('id=5')->save($data);?//?根據條件保存修改的數據`### 快捷查詢
新版增加了快捷查詢方式,可以進一步簡化查詢條件的寫法,例如:
**一、實現不同字段相同的查詢條件**`$User?=?M("User");?//?實例化User對象<br class="calibre5"></br>$map['name|title']?=?'thinkphp';<br class="calibre5"></br>//?把查詢條件傳入查詢方法<br class="calibre5"></br>$User->where($map)->select();?`查詢條件就變成name='thinkphp' OR title = 'thinkphp'
**二、實現不同字段不同的查詢條件**`$User?=?M("User");?//?實例化User對象<br class="calibre5"></br>$map['status&title;']?=array('1','thinkphp','_multi'=>true);<br class="calibre5"></br>//?把查詢條件傳入查詢方法<br class="calibre5"></br>$User->where($map)->select();?`'_multi'=>true必須加在數組的最后,表示當前是多條件匹配,這樣查詢條件就變成status=1 AND title = 'thinkphp' ,查詢字段支持更多的,例如:
$map['status&score;&title;']=array('1',array('gt','0'),'thinkphp','_multi'=>true);
查詢條件就變成status=1 AND score >0 AND title = 'thinkphp'
注意:快捷查詢方式中“|”和“&”不能同時使用。### 區間查詢
ThinkPHP支持對某個字段的區間查詢,例如: `$map['id']?=?array(array('gt',1),array('lt',10))?;`得到的查詢條件是:(`id` > 1) AND (`id` < 10)`$map['id']?=?array(array('gt',3),array('lt',10),?'or')?;`得到的查詢條件是: (`id` > 3) OR (`id` < 10)`$map['id']??=?array(array('neq',6),array('gt',3),'and');?`得到的查詢條件是:(`id` != 6) AND (`id` > 3)
最后一個可以是AND、 OR或者 XOR運算符,如果不寫,默認是AND運算。
區間查詢的條件可以支持普通查詢的所有表達式,也就是說類似LIKE、GT和EXP這樣的表達式都可以支持。另外區間查詢還可以支持更多的條件,只要是針對一個字段的條件都可以寫到一起,例如:`$map['name']??=?array(array('like','%a%'),?array('like','%b%'),?array('like','%c%'),?'ThinkPHP','or');?`最后的查詢條件是:`(`name`?LIKE?'%a%')?OR?(`name`?LIKE?'%b%')?OR?(`name`?LIKE?'%c%')?OR?(`name`?=?'ThinkPHP')`### 組合查詢
如果你需要在查詢的時候同時偶爾使用字符串卻又不希望丟失數組方式的靈活的話,可以考慮使用組合查詢。
組合查詢的主體還是采用數組方式查詢,只是加入了一些特殊的查詢支持,包括字符串模式查詢(_string)、復合查詢(_complex)、請求字符串查詢(_query),混合查詢中的特殊查詢每次查詢只能定義一個,由于采用數組的索引方式,索引相同的特殊查詢會被覆蓋。
**一、字符串模式查詢**(采用_string 作為查詢條件)
數組條件還可以和字符串條件混合使用,例如:`$User?=?M("User");?//?實例化User對象<br class="calibre5"></br>$map['id']?=?array('neq',1);<br class="calibre5"></br>$map['name']?=?'ok';<br class="calibre5"></br>$map['_string']?=?'status=1?AND?score>10';<br class="calibre5"></br>$User->where($map)->select();?`最后得到的查詢條件就成了:
( `id` != 1 ) AND ( `name` = 'ok' ) AND ( status=1 AND score>10 )
**二、請求字符串查詢方式**
請求字符串查詢是一種類似于URL傳參的方式,可以支持簡單的條件相等判斷。`$map['id']?=?array('gt','100');<br class="calibre5"></br>$map['_query']?=?'status=1&score;=100&_logic=or';`得到的查詢條件是:`id`>100 AND (`status` = '1' OR `score` = '100')
**三、復合查詢**
復合查詢相當于封裝了一個新的查詢條件,然后并入原來的查詢條件之中,所以可以完成比較復雜的查詢條件組裝。
例如: `$where['name']??=?array('like',?'%thinkphp%');<br class="calibre5"></br>$where['title']??=?array('like','%thinkphp%');<br class="calibre5"></br>$where['_logic']?=?'or';<br class="calibre5"></br>$map['_complex']?=?$where;<br class="calibre5"></br>$map['id']??=?array('gt',1);`查詢條件是
(id>1)AND( (namelike'%thinkphp%')OR(titlelike'%thinkphp%') )
復合查詢使用了_complex作為子查詢條件來定義,配合之前的查詢方式,可以非常靈活的制定更加復雜的查詢條件。
很多查詢方式可以相互轉換,例如上面的查詢條件可以改成:`$where['id']?=?array('gt',1);<br class="calibre5"></br>$where['_string']?=?'?(name?like?"%thinkphp%")??OR?(?title?like?"%thinkphp")?';`最后生成的SQL語句是一致的。### 統計查詢
在應用中我們經常會用到一些統計數據,例如當前所有(或者滿足某些條件)的用戶數、所有用戶的最大積分、用戶的平均成績等等,ThinkPHP為這些統計操作提供了一系列的內置方法,包括:方法 說明 Count 統計數量,參數是要統計的字段名(可選) Max 獲取最大值,參數是要統計的字段名(必須) Min 獲取最小值,參數是要統計的字段名(必須) Avg 獲取平均值,參數是要統計的字段名(必須) Sum 獲取總分,參數是要統計的字段名(必須) 用法示例:`$User?=?M("User");?//?實例化User對象`獲取用戶數:`$userCount?=?$User->count();`或者根據字段統計:`$userCount?=?$User->count("id");`獲取用戶的最大積分:`$maxScore?=?$User->max('score');`獲取積分大于0的用戶的最小積分:`$minScore?=?$User->where('score>0')->min('score');`獲取用戶的平均積分:`$avgScore?=?$User->avg('score');`統計用戶的總成績:`$sumScore?=?$User->sum('score');`并且所有的統計查詢均支持連貫操作的使用。### 定位查詢
ThinkPHP支持定位查詢,但是要求當前模型必須繼承高級模型類才能使用,可以使用getN方法直接返回查詢結果中的某個位置的記錄。例如:
獲取符合條件的第3條記錄:`$User->where('score>0')->order('score?desc')->getN(2);`獲取符合條件的最后第二條記錄:`$User->?where('score>80')->order('score?desc')->getN(-2);`獲取第一條記錄:`$User->where('score>80')->order('score?desc')->first();`獲取最后一條記錄:`$User->where('score>80')->order('score?desc')->last();`### SQL查詢
ThinkPHP內置的ORM和ActiveRecord模式實現了方便的數據存取操作,而且新版增加的連貫操作功能更是讓這個數據操作更加清晰,但是ThinkPHP仍然保留了原生的SQL查詢和執行操作支持,為了滿足復雜查詢的需要和一些特殊的數據操作,SQL查詢的返回值因為是直接返回的Db類的查詢結果,沒有做任何的處理。主要包括下面兩個方法:
**1、query方法**query 執行SQL查詢操作 用法 query($sql,$parse=false) 參數 query(必須):要查詢的SQL語句
parse(可選):是否需要解析SQL 返回值 如果數據非法或者查詢錯誤則返回false
否則返回查詢結果數據集(同select方法)
使用示例: `$Model?=?new?Model()?//?實例化一個model對象?沒有對應任何數據表<br class="calibre5"></br>$Model->query("select?*?from?think_user?where?status=1");`如果你當前采用了分布式數據庫,并且設置了讀寫分離的話,query方法始終是在讀服務器執行,因此query方法對應的都是讀操作,而不管你的SQL語句是什么。**2、execute方法**execute用于更新和寫入數據的sql操作 用法 execute($sql,$parse=false) 參數 query(必須):要執行的SQL語句
parse(可選):是否需要解析SQL 返回值 如果數據非法或者查詢錯誤則返回false
否則返回影響的記錄數 使用示例: `$Model?=?new?Model()?//?實例化一個model對象?沒有對應任何數據表<br class="calibre5"></br>$Model->execute("update?think_user?set?name='thinkPHP'?where?status=1");`如果你當前采用了分布式數據庫,并且設置了讀寫分離的話,execute方法始終是在寫服務器執行,因此execute方法對應的都是寫操作,而不管你的SQL語句是什么。**3、其他技巧**
自動獲取當前表名
通常使用原生SQL需要手動加上當前要查詢的表名,如果你的表名以后會變化的話,那么就需要修改每個原生SQL查詢的sql語句了,針對這個情況,系統還提供了一個小的技巧來幫助解決這個問題。
例如:`$model?=?M("User");<br class="calibre5"></br>$model->query('select?*?from?__TABLE__?where?status>1');`我們這里使用了__TABLE__ 這樣一個字符串,系統在解析的時候會自動替換成當前模型對應的表名,這樣就可以做到即使模型對應的表名有所變化,仍然不用修改原生的sql語句。
支持連貫操作和SQL解析
新版對query和execute兩個原生SQL操作方法增加第二個參數支持, 表示是否需要解析SQL (默認為false 表示直接執行sql ),如果設為true 則會解析SQL中的特殊字符串 (需要配合連貫操作)。
例如,支持 如下寫法:`$model->table("think_user")<br class="calibre5"></br>??????->where(array("name"=>"thinkphp"))<br class="calibre5"></br>??????->field("id,name,email")<br class="calibre5"></br>??????->query('select?%FIELD%?from?%TABLE%?%WHERE%',true);`其中query方法中的%FIELD%、%TABLE%和%WHERE%字符串會自動替換為同名的連貫操作方法的解析結果SQL,支持的替換字符串包括:替換字符串 對應連貫操作方法 %FIELD% field %TABLE% table %DISTINCT% distinct %WHERE% where %JOIN% join %GROUP% group %HAVING% having %ORDER% order %LIMIT% limit %UNION% union### 動態查詢
借助PHP5語言的特性,ThinkPHP實現了動態查詢,包括下面幾種:方法名 說明 舉例 getBy 根據某個字段的值查詢數據 例如,getByName,getByEmail getFieldBy 根據某個字段查詢并返回某個字段的值 例如,getFieldByName top 獲取前多少條記錄(需要高級模型支持) 例如,top8,top12 **一、getBy動態查詢**
該查詢方式針對數據表的字段進行查詢。例如,User對象擁有id,name,email,address 等屬性,那么我們就可以使用下面的查詢方法來直接根據某個屬性來查詢符合條件的記錄。 `$user?=?$User->getByName('liu21st');<br class="calibre5"></br>$user?=?$User->getByEmail('liu21st@gmail.com');<br class="calibre5"></br>$user?=?$User->getByAddress('中國深圳');`暫時不支持多數據字段的動態查詢方法,請使用find方法和select方法進行查詢。**二、getFieldBy動態查詢**
針對某個字段查詢并返回某個字段的值,例如`$user?=?$User->getFieldByName('liu21st','id');`表示根據用戶的name獲取用戶的id值。**三、top動態查詢**
ThinkPHP還提供了另外一種動態查詢方式,就是獲取符合條件的前N條記錄(和定位查詢一樣,也要求當前模型類必須繼承高級模型類后才能使用)。例如,我們需要獲取當前用戶中積分大于0,積分最高的前5位用戶 :`$User->?where('score>80')->order('score?desc')->top5();`要獲取積分的前8位可以改成:`$User->?where('score>80')->order('score?desc')->top8();`### 子查詢
新版新增了子查詢支持,有兩種使用方式:
**1、使用select方法**
當select方法的參數為false的時候,表示不進行查詢只是返回構建SQL,例如: `//?首先構造子查詢SQL?<br class="calibre5"></br>$subQuery?=?$model->field('id,name')->table('tablename')->group('field')->where($where)->order('status')->select(false);?`**2、使用buildSql方法**`$subQuery?=?$model->field('id,name')->table('tablename')->group('field')->where($where)->order('status')->buildSql();?`調用buildSql方法后不會進行實際的查詢操作,而只是生成該次查詢的SQL語句(為了避免混淆,會在SQL兩邊加上括號),然后我們直接在后續的查詢中直接調用。`//?利用子查詢進行查詢?<br class="calibre5"></br>$model->table($subQuery.'?a')->where()->order()->select()?`構造的子查詢SQL可用于TP的連貫操作方法,例如table where等。
[上一頁](71.html "上一頁")[下一頁](73.html "下一頁")
- 序言
- 1. 入門
- 1.1 簡介
- 1.2 基礎概念
- 1.3 獲取ThinkPHP
- 1.4 環境要求
- 1.5 許可協議
- 1.6 目錄結構
- 1.7 命名規范
- 1.8 MVC分層
- 1.9 CBD架構
- 1.10 特性概述
- 1.11 系統流程
- 1.12 開發流程
- 2. 入口
- 2.1 入口文件
- 2.2 項目目錄
- 2.3 部署目錄
- 2.4 項目編譯
- 2.5 調試模式
- 3. 配置
- 3.1 配置格式
- 3.2 慣例配置
- 3.3 項目配置
- 3.4 調試配置
- 3.5 分組配置
- 3.6 讀取配置
- 3.7 動態配置
- 3.8 擴展配置
- 4. 函數和類庫
- 4.1 函數庫
- 4.2 類庫
- 5. 控制器
- 5.1 URL模式
- 5.2 模塊和操作
- 5.3 定義控制器
- 5.4 空操作
- 5.5 空模塊
- 5.6 模塊分組
- 5.7 URL偽靜態
- 5.8 URL路由
- 5.9 URL重寫
- 5.10 URL生成
- 5.11 URL大小寫
- 5.12 前置和后置操作
- 5.13 跨模塊調用
- 5.14 頁面跳轉
- 5.15 重定向
- 5.16 獲取系統變量
- 5.17 判斷請求類型
- 5.18 獲取URL參數
- 5.19 AJAX返回
- 5.20 Action參數綁定
- 5.21 多層控制器支持
- 6. 模型
- 6.1 模型定義
- 6.2 模型實例化
- 6.3 字段定義
- 6.4 數據主鍵
- 6.5 屬性訪問
- 6.6 跨庫操作
- 6.7 連接數據庫
- 6.8 切換數據庫
- 6.9 分布式數據庫
- 6.10 創建數據
- 6.11 字段映射
- 6.12 連貫操作
- 6.13 CURD操作
- 6.14 ActiveRecord
- 6.15 自動驗證
- 6.16 命名范圍
- 6.17 自動完成
- 6.18 查詢語言
- 6.19 查詢鎖定
- 6.20 字段排除
- 6.21 事務支持
- 6.22 高級模型
- 6.23 視圖模型
- 6.24 關聯模型
- 6.25 Mongo模型
- 6.26 動態模型
- 6.27 虛擬模型
- 6.28 多層模型支持
- 7. 視圖
- 7.1 模板定義
- 7.2 模板賦值
- 7.3 模板輸出
- 7.4 模板替換
- 7.5 獲取內容
- 7.6 模板引擎
- 7.7 布局模板
- 8. 模板引擎
- 8.1 變量輸出
- 8.2 系統變量
- 8.3 使用函數
- 8.4 默認值輸出
- 8.5 使用運算符
- 8.6 內置標簽
- 8.7 包含文件
- 8.8 導入文件
- 8.9 Volist標簽
- 8.10 Foreach標簽
- 8.11 For標簽
- 8.12 Switch標簽
- 8.13 比較標簽
- 8.14 三元運算
- 8.15 范圍判斷標簽
- 8.16 Present標簽
- 8.17 Empty標簽
- 8.18 Defined標簽
- 8.19 Define標簽
- 8.20 Assign標簽
- 8.21 IF標簽
- 8.22 標簽嵌套
- 8.23 使用PHP代碼
- 8.24 模板布局
- 8.25 模板繼承
- 8.26 原樣輸出
- 8.27 模板注釋
- 8.28 引入標簽庫
- 8.29 修改定界符
- 8.30 避免JS混淆
- 9. 日志
- 9.1 日志級別
- 9.2 記錄方式
- 9.3 手動記錄
- 10. 錯誤
- 10.1 異常處理
- 10.2 異常模板
- 10.3 異常顯示
- 11. 調試
- 11.1 運行狀態
- 11.2 頁面Trace
- 11.3 調試方法
- 12. 緩存
- 12.1 緩存方式
- 12.2 動態緩存
- 12.3 緩存隊列
- 12.4 快捷緩存
- 12.5 快速緩存
- 12.6 查詢緩存
- 12.7 SQL解析緩存
- 12.8 靜態緩存
- 13. 擴展
- 13.1 行為擴展
- 13.2 類庫擴展
- 13.3 控制器擴展
- 13.4 模型擴展
- 13.5 驅動擴展
- 13.6 Widget擴展
- 13.7 模式擴展
- 13.8 引擎擴展
- 14. 安全
- 14.1 表單令牌
- 14.2 字段類型驗證
- 14.3 防止SQL注入
- 14.4 輸入過濾
- 14.5 上傳安全
- 14.6 防止XSS攻擊
- 14.7 其他安全建議
- 14.8 目錄安全文件
- 14.9 保護模板文件
- 15. 性能
- 15.1 關閉調試模式
- 15.2 開啟緩存
- 15.3 合并字段緩存
- 15.4 優化SQL
- 15.5 替換入口
- 15.6 前端優化
- 16. 部署
- 16.1 PATH_INFO支持
- 16.2 隱藏index.php
- 16.3 二級域名部署
- 16.4 定制錯誤頁面
- 16.5 設置時區
- 17. SAE支持
- 17.1 SAE介紹
- 17.2 獲取SAE
- 17.3 SAE開發
- 18. REST支持
- 18.1 REST介紹
- 18.2 REST模式
- 18.3 REST配置
- 18.4 REST路由
- 18.5 REST方法
- 19. 雜項
- 19.1 Session支持
- 19.2 Cookie支持
- 19.3 日期和時間
- 19.4 WML開發
- 19.5 多語言
- 19.6 數據分頁
- 19.7 文件上傳
- 19.8 驗證碼
- 19.9 圖片添加水印
- 19.10 IP獲取和定位
- 20. 附錄
- 20.1 常量參考
- 20.2 配置參考
- 20.3 關于升級
- 20.4 大事記
- 鳴謝
- 關于