### 2018 年 11 月 22 日 發(fā)布
>[danger] 今天是感恩節(jié),首先感謝所有關(guān)注和使用`ThinkPHP`的用戶,尤其要對(duì)那些為框架做過(guò)貢獻(xiàn)的用戶說(shuō)聲感恩,因?yàn)橛心銈兊拇罅χС?,`ThinkPHP`才能堅(jiān)持到今天還在不斷更新完善,我也還能寫(xiě)下這篇博客。
本文給大家不完全的整理了一些能夠提高開(kāi)發(fā)效率的查詢技巧,希望能給你的開(kāi)發(fā)工作帶來(lái)更多的方便,不過(guò)也許有些技巧可能你已經(jīng)了然于胸了,就當(dāng)鞏固學(xué)習(xí)了。
>[info] 本文中所有的查詢示例都以模型用法為例,只為為了進(jìn)一步說(shuō)明所有的查詢構(gòu)造器用法都適用于模型。
## 查詢值為Null的數(shù)據(jù)
```
// 查詢email為空,并且name不為空的用戶數(shù)據(jù)
User::whereNull('email')
->whereNotNull('name')
->select();
```
## 多個(gè)字段同一個(gè)查詢條件
快捷查詢方式是一種多字段相同查詢條件的簡(jiǎn)化寫(xiě)法,可以進(jìn)一步簡(jiǎn)化查詢條件的寫(xiě)法,在多個(gè)字段之間用`|`分割表示`OR`查詢,用`&`分割表示`AND`查詢,例如:
```
User::where('name|title','like','thinkphp%')
->where('create_time&update_time','>',0)
->find();
```
## 數(shù)組對(duì)象查詢
如果你升級(jí)老版本的系統(tǒng)到`5.1`,由于數(shù)組查詢方式的變化,而你又不希望全部換成表達(dá)式查詢,那么可以使用數(shù)組對(duì)象查詢。
```
use think\db\Where;
// 5.0的數(shù)組查詢條件
$map = [
'name' => ['like', 'thinkphp%'],
'title' => ['like', '%think%'],
'id' => ['>', 10],
'status' => 1,
];
User::where(new Where($map))
->select();
```
只需要把原來(lái)的
```
where($map)
```
改成
```
where(new Where($map))
```
即可完成簡(jiǎn)單的數(shù)組查詢升級(jí)兼容。
## 使用快捷方法
對(duì)于一些常用的查詢,系統(tǒng)封裝了快捷查詢方法,例如:
```
User::whereIn('id', [1,2,3])
->whereLike('name', 'think%')
->select();
```
相當(dāng)于下面的查詢
```
User::where('id', 'in', [1,2,3])
->where('name', 'like', 'think%')
->select();
```
更多的方法可以參考官方手冊(cè)或者使用IDE的自動(dòng)提示。
## 獲取字段值和列數(shù)據(jù)
對(duì)于一些簡(jiǎn)單的數(shù)據(jù)獲取,你完全不需要查詢整個(gè)表的數(shù)據(jù),例如查詢某個(gè)字段(滿足條件的)值或者列數(shù)據(jù)。
```
// 獲取id為10的用戶名稱
User::where('id', 10)
->value('name');
// 獲取狀態(tài)為1的用戶名稱列表
User::where('status', 1)
->column('name');
// 獲取分?jǐn)?shù)大于80的用戶分?jǐn)?shù)列表,以用戶ID為索引
User::where('score', '>', 80)
->column('score', 'id');
```
## 聚合查詢
可以直接進(jìn)行各種聚合查詢,包括:
```
User::count();
User::max('score');
User::min('score');
User::avg('score');
Blog::sum('read_count');
```
如果你的`min`/`max`查詢的是一個(gè)字符串類型字段,記得加上第二個(gè)參數(shù)。
```
// 獲取name字段的最大值
User::max('name', false);
```
## 時(shí)間區(qū)間查詢
時(shí)間查詢主要用于時(shí)間字段的區(qū)間查詢,支持所有類型的時(shí)間字段。
```
// 大于某個(gè)時(shí)間
User::whereTime('birthday', '>=', '2008-10-1')
->select();
// 小于某個(gè)時(shí)間
User::whereTime('birthday', '<', '2000-10-1')
->select();
// 時(shí)間區(qū)間查詢
User::whereBetweenTime('birthday', '1990-10-1', '2000-10-1')
->select();
// 不在某個(gè)時(shí)間區(qū)間
User::whereNotBetweenTime('birthday', '1970-10-1', '2000-10-1')
->select();
```
如果`whereBetweenTime`方法沒(méi)有指定第三個(gè)參數(shù),則表示查詢當(dāng)天的數(shù)據(jù)
```
// 查詢2000年10月1日出生的用戶
User::whereBetweenTime('birthday', '2000-10-1')
->select();
```
## 時(shí)間表達(dá)式查詢
對(duì)于一些非具體的時(shí)間查詢,比較適合使用時(shí)間表達(dá)式進(jìn)行查詢,例如:
```
// 獲取今天的博客
Blog::whereTime('create_time', 'today')
->select();
// 獲取昨天的博客
Blog::whereTime('create_time', 'yesterday')
->select();
// 獲取本周的博客
Blog::whereTime('create_time', 'week')
->select();
// 獲取上周的博客
Blog::whereTime('create_time', 'last week')
->select();
// 獲取本月的博客
Blog::whereTime('create_time', 'month')
->select();
// 獲取上月的博客
Blog::whereTime('create_time', 'last month')
->select();
// 獲取今年的博客
Blog::whereTime('create_time', 'year')
->select();
// 獲取去年的博客
Blog::whereTime('create_time', 'last year')
->select();
```
高級(jí)的時(shí)間表達(dá)式查詢可以使用PHP的[相對(duì)時(shí)間格式](http://php.net/manual/zh/datetime.formats.relative.php),例如:
```
// 查詢兩天以內(nèi)的博客
Blog::whereTime('create_time','-2 days')
->select();
// 查詢昨天中午后發(fā)的博客
Blog::whereTime('create_time','yesterday noon')
->select();
```
更多的時(shí)間表達(dá)式查詢你可以自由發(fā)揮。
## 時(shí)間字段范圍查詢
你可以查詢當(dāng)前時(shí)間是否在兩個(gè)時(shí)間字段區(qū)間范圍內(nèi),通常用于一些活動(dòng)以及優(yōu)惠券的有效期查詢等等。
```
// 查詢有效期內(nèi)的活動(dòng)
Event::whereBetweenTimeField('start_time','end_time')
->select();
// 查詢沒(méi)有開(kāi)始或者已經(jīng)過(guò)期的活動(dòng)
Event::whereNotBetweenTimeField('start_time','end_time')
->select();
```
## 字段比較
可以直接比較兩個(gè)字段的大小進(jìn)行查詢
```
User::whereColumn('update_time', '>', 'create_time')
->select();
User::whereColumn('score1', '>', 'score2')
->select();
```
如果需要比較兩個(gè)字段相同,可以使用
```
User::whereColumn('score1', 'score2')
->select();
```
## 動(dòng)態(tài)查詢
使用動(dòng)態(tài)查詢可以進(jìn)一步簡(jiǎn)化你的查詢條件,不過(guò)缺點(diǎn)是可能無(wú)法做到IDE的自動(dòng)提示了,例如:
```
// 根據(jù)郵箱(email)查詢用戶信息
User::whereEmail('thinkphp@qq.com')
->find();
// 根據(jù)昵稱(nick_name)查詢用戶
User::whereNickName('like', '%流年%')
->select();
// 根據(jù)郵箱查詢用戶信息
User::getByEmail('thinkphp@qq.com');
// 根據(jù)昵稱(nick_name)查詢用戶信息
User::getByNickName('流年');
// 根據(jù)郵箱查詢用戶的昵稱
User::getFieldByEmail('thinkphp@qq.com', 'nick_name');
// 根據(jù)昵稱(nick_name)查詢用戶郵箱
User::getFieldByNickName('流年', 'email');
```
## 條件查詢
利用條件查詢你可以很方便的控制查詢條件分支,你再也不需要在組裝查詢條件的時(shí)候?qū)懘罅康腵if`和`else`了。
```
User::when($condition, function ($query) {
// 滿足條件后執(zhí)行
$query->where('score', '>', 80)->limit(10);
})->select();
```
并且支持不滿足條件的分支查詢,并且支持多次調(diào)用`when`方法。
```
User::when($condition, function ($query) {
// 滿足條件后執(zhí)行
$query->where('score', '>', 80)->limit(10);
}, function ($query) {
// 不滿足條件執(zhí)行
$query->where('score', '>', 60);
});
```
## JSON查詢
如果你的字段類型使用的是JSON類型,那么可以直接使用框架提供的JSON查詢支持。
```
User::where('info->nickname', 'ThinkPHP')
->find();
```
注意,需要在模型里面定義`JSON`字段屬性。
```
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// 設(shè)置json類型字段
protected $json = ['info'];
}
```
如果使用Db查詢的話,可以改為
```
$user = Db::name('user')
->json(['info'])
->where('info->nickname','ThinkPHP')
->find();
```
## SQL函數(shù)查詢
如果需要對(duì)某個(gè)字段使用SQL函數(shù)表達(dá)式查詢,可以使用
```
User::whereExp('nickname', "= CONCAT(name, '-', id)")
->whereRaw('LEFT(nickname, 5) = ?', ['think'])
->select();
```
注意`whereExp`和`whereRaw`方法的區(qū)別,前者是對(duì)某個(gè)字段使用SQL函數(shù)表達(dá)式,后者是整個(gè)查詢就是一個(gè)SQL函數(shù)表達(dá)式。
## 字段遞增/遞減
單獨(dú)對(duì)某個(gè)字段進(jìn)行遞增/遞減操作,可以用:
```
// score 字段加 1
User::where('id', 1)
->setInc('score');
// score 字段加 5
User::where('id', 1)
->setInc('score', 5);
// score 字段減 1
User::where('id', 1)
->setDec('score');
// score 字段減 5
User::where('id', 1)
->setDec('score', 5);
```
可以支持延時(shí)更新
```
// 延時(shí)30秒更新score字段
User::where('id', 1)->setInc('score', 1, 30);
```
如果需要同時(shí)遞增/遞減多個(gè)字段的話,可以使用:
```
// 博客的閱讀數(shù)遞增1 評(píng)論數(shù)遞減2
Blog::where('id', 10)
->inc('read_count')
->dec('comment_count', 2)
->update();
```
## 指定字段值排序
如果你需要按照指定字段的值的順序來(lái)排序,可以使用
```
User::where('status', 1)
->orderField('id', [1,2,3])
->select();
```
## 從主庫(kù)讀取
如果你使用了數(shù)據(jù)庫(kù)的主從分離,當(dāng)剛寫(xiě)入數(shù)據(jù)后,數(shù)據(jù)庫(kù)的主從同步可能還沒(méi)來(lái)得及同步,這個(gè)時(shí)候立刻查詢數(shù)據(jù)可能會(huì)出錯(cuò),你可以使用下面的方法從主庫(kù)讀取。
```
$user = User::create($data);
$user->readMaster()->select();
```
你可以全局配置數(shù)據(jù)寫(xiě)入后自動(dòng)讀取主庫(kù)
```
// 模型寫(xiě)入后自動(dòng)讀取主服務(wù)器
'read_master' => true,
```
## 獲取自增ID
使用`Db`類的`insert`方法或者模型的`save`方法返回的不是自增主鍵,不過(guò)你可以使用。
```
$userId = Db::name('user')->insertGetId($data);
```
如果使用模型的話,自增主鍵的值會(huì)自動(dòng)賦值給模型對(duì)象,可以直接獲取。
```
$user = User::create($data);
echo $user->id;
```
## 模型查詢?yōu)榭盏奶幚?
模型查詢數(shù)據(jù)不存在的話返回值為Null,所以必須要添加返回值判斷然后進(jìn)行數(shù)據(jù)處理,如果你不想手動(dòng)判斷,可以使用下面的方法查詢,如果數(shù)據(jù)不存在則返回空的模型對(duì)象。
```
// 始終返回模型對(duì)象
$user = User::where('id', 10)->findOrEmpty();
```
## 自動(dòng)分批寫(xiě)入
如果你需要一次寫(xiě)入大量數(shù)據(jù),建議使用`limit`方法自動(dòng)分批多次寫(xiě)入。
```
// 自動(dòng)分批多次寫(xiě)入數(shù)據(jù)庫(kù) 每次最多寫(xiě)入1000條
Db::name('user')
->limit(1000)
->insertAll($dataList);
```
如果是使用模型的話,建議直接使用`saveAll`方法而不需要`limit`方法。
```
$user = new User;
$user->saveAll($dataList);
```
## 數(shù)據(jù)分批處理
對(duì)于大量數(shù)據(jù)的處理操作,可以使用`chunk`分批處理方法。
```
// 每次處理100個(gè)數(shù)據(jù)
User::chunk(100, function($users) {
foreach ($users as $user) {
// 處理數(shù)據(jù)
}
});
```
## 游標(biāo)查詢
對(duì)于內(nèi)存開(kāi)銷比較大的應(yīng)用,在做大量數(shù)據(jù)查詢和處理的時(shí)候,使用`cursor`方法進(jìn)行游標(biāo)查詢,可以利用PHP的生成器特性,減少內(nèi)存占用。
```
$cursor = User::cursor();
foreach($cursor as $user){
// 處理數(shù)據(jù)
}
```
## 總結(jié)
善于運(yùn)用查詢構(gòu)造器封裝的快捷方法,可以大大提高開(kāi)發(fā)效率,讓你更專注于業(yè)務(wù)邏輯,而不是怎么寫(xiě)查詢代碼。
另外模型的很多功能都是為了提高開(kāi)發(fā)效率而設(shè)計(jì)的,這里涉及太多的技巧,就不再一一描述了,以后專門來(lái)講吧。
- 值得升級(jí)到5.1的18個(gè)理由
- 5.1.7版本新特性
- JSON字段類型在ORM中的使用
- 文件下載響應(yīng)對(duì)象
- 教你使用5.1的數(shù)組對(duì)象查詢
- 模型三大利器之一:搜索器
- 在ThinkPHP中使用Yaconf
- 掌握命令行的表格輸出
- 5.1.25查詢參數(shù)綁定的改進(jìn)
- ThinkPHP安全規(guī)范指引
- 巧用數(shù)據(jù)集的排序功能實(shí)現(xiàn)統(tǒng)計(jì)排序
- think-orm ——基于5.1的獨(dú)立ORM庫(kù)
- think-template——基于ThinkPHP的獨(dú)立模板引擎
- ThinkPHP5.1.26版本發(fā)布——修正版本,包含安全更新
- ThinkPHP5.0和3.2再發(fā)安全更新
- 官宣:ThinkPHP發(fā)布首個(gè)LTS版本
- 你真的了解Db類和模型的正確使用姿勢(shì)么?
- 如何更有效的記錄和管理日志
- 模型三大利器之二:修改器
- ThinkPHP5.1.28版本發(fā)布——修正上一版本問(wèn)題,改進(jìn)關(guān)聯(lián)查詢
- 模型三大利器之三:獲取器
- API版本控制的幾種思路
- ThinkPHP5.2第一個(gè)Beta版本發(fā)布測(cè)試
- 讓你少犯錯(cuò)的數(shù)據(jù)查詢基本原則
- ThinkPHP發(fā)布5.1.29版本——常規(guī)更新
- 這15個(gè)好習(xí)慣讓你更容易升級(jí)到5.2
- 如何有效提高ThinkPHP的應(yīng)用性能
- 讓你提高開(kāi)發(fā)效率的查詢技巧
- 模型關(guān)聯(lián)查詢不完全指南
- 5.2發(fā)布Beta2版本——統(tǒng)一和精簡(jiǎn)大量用法
- ThinkPHP發(fā)布5.1.30版本——支持微秒時(shí)間字段寫(xiě)入
- ThinkPHP的數(shù)據(jù)緩存使用
- ThinkPHP5.2安裝及入口文件
- ThinkPHP榮獲2018 年度最受歡迎中國(guó)開(kāi)源開(kāi)發(fā)框架第1名
- 5.1路由使用心得技巧
- ThinkPHP5.*版本發(fā)布安全更新
- ThinkPHP項(xiàng)目及代碼規(guī)范指北
- 5.2版本的設(shè)計(jì)規(guī)范指導(dǎo)
- ThinkPHP5.1.32版本發(fā)布——圣誕快樂(lè)
- 利用Trait特性給模型增加樂(lè)觀鎖功能
- 5.2數(shù)據(jù)庫(kù)和模型的變化(摘要)
- ThinkPHP模板引擎實(shí)現(xiàn)和常見(jiàn)問(wèn)題
- ThinkPHP5.0.24版本發(fā)布——安全更新
- 不忘初心,方得始終——ThinkPHP十三周年報(bào)告
- ThinkPHP5+相關(guān)資源匯總
- 異步社區(qū)ThinkPHP周年慶專享優(yōu)惠活動(dòng)
- 5.2路由的調(diào)整和改進(jìn)
- ThinkPHP發(fā)布5.1.33版本——包含安全更新
- ThinkPHP擴(kuò)展開(kāi)發(fā)指南
- ThinkPHP發(fā)布5.2Beta3版本
- ThinkPHP發(fā)布5.1.34版本——喜迎新年
- ThinkPHP發(fā)布5.2RC1版本
- ThinkPHP發(fā)布5.1.35版本——常規(guī)更新
- 5.2配置類的調(diào)整
- 5.2時(shí)間查詢的改進(jìn)和優(yōu)化
- 5.2RC版本升級(jí)不完全指導(dǎo)(僅供學(xué)習(xí)參考)
- ThinkPHP5.2版本正式變更為6.0版本
- ThinkPHP百度云云虛擬主機(jī)專享免費(fèi)活動(dòng)
- 事件系統(tǒng)以及查詢事件、模型事件的使用
- ThinkPHP6.0RC2版本發(fā)布——架構(gòu)升級(jí)、精簡(jiǎn)核心
- ThinkPHP5.1.36LTS版本發(fā)布——常規(guī)更新
- 新版Session和Cookie設(shè)計(jì)變化
- ThinkPHP5.1.37版本發(fā)布——常規(guī)更新
- ThinkPHP6.0RC3版本發(fā)布——細(xì)節(jié)完善,體驗(yàn)優(yōu)化
- 6.0中間件使用詳解
- Composer各大廠商鏡像地址
- ThinkPHP6.0發(fā)布計(jì)劃公告
- 「ThinkPHP開(kāi)發(fā)者周刊」招募志愿者
- ThinkPHP6.0日志變化
- ThinkPHP5.1.38版本發(fā)布——常規(guī)更新
- ThinkPHP6.0RC4版本發(fā)布——ORM獨(dú)立,日志多通道支持
- ThinkORM2.0開(kāi)發(fā)指南上線
- ThinkPHP6.0RC5版本發(fā)布——多應(yīng)用模式獨(dú)立,中間件機(jī)制調(diào)整
- ThinkPHP6.0版本發(fā)布——程序員節(jié)福利
- ThinkPHP5.1.39LTS版本發(fā)布——常規(guī)更新
- ThinkPHP6.0.1版本發(fā)布——圣誕快樂(lè)!
- 回顧2019,展望2020!
- ThinkPHPV6.0.2版本發(fā)布——2020新春快樂(lè)!
- 周年福利系列:Swoole合作優(yōu)惠
- 億速云成為ThinkPHPV6.0獨(dú)家贊助發(fā)布商??
- 新冠疫情工具和限免資源專題(保持更新中)
- 周年福利系列:創(chuàng)宇信用認(rèn)證合作優(yōu)惠
- 周年福利系列:碼云企業(yè)版限時(shí)10%優(yōu)惠
- 周年福利系列:想天短說(shuō)抵現(xiàn)優(yōu)惠
- think-swoole直播:從零開(kāi)始掌握swoole開(kāi)發(fā)
- 周年福利系列:B2C開(kāi)源電商ShopXO授權(quán)8折優(yōu)惠
- 周年福利系列:LayuiAdmin 永久授權(quán)限時(shí)優(yōu)惠
- ThinkPHP資源導(dǎo)航站上線——構(gòu)建生態(tài) 服務(wù)未來(lái)
- ThinkPHP官方技術(shù)支持服務(wù)和應(yīng)用服務(wù)市場(chǎng)上線公測(cè)
- ThinkPHP市場(chǎng)精選——推廣基本要素
- ThinkPHP市場(chǎng)精選——客服聊天專題
- ThinkPHPV6.0.3版本發(fā)布——端午安康
- ThinkPHP開(kāi)發(fā)者扶持計(jì)劃
- 6.0.3版本關(guān)鍵更新及升級(jí)事項(xiàng)
- 「ThinkPHP開(kāi)發(fā)者周刊」改版重啟
- ThinkPHP市場(chǎng)精選——企業(yè)建站專題
- ThinkPHP 提供統(tǒng)一API接口服務(wù)
- ThinkPHP市場(chǎng)精選——直播電商專題
- ThinkAPI服務(wù)SDK發(fā)布
- 官方服務(wù)市場(chǎng)啟用獨(dú)立子域名
- ThinkPHP市場(chǎng)精選——刷臉支付專題
- ThinkAPI推出會(huì)員服務(wù)計(jì)劃
- ThinkPHPV6.0.4版本發(fā)布——中秋國(guó)慶雙節(jié)快樂(lè)
- ThinkPHPV5.1.40版本發(fā)布——常規(guī)更新
- 1024程序員節(jié)福利走一波
- ThinkPHP V6.0.5版本發(fā)布——兼容Composer2.0
- 知識(shí)圖譜應(yīng)用場(chǎng)景——源論技術(shù)沙龍
- ThinkPHP5.*版本改進(jìn)Composer2.0的兼容
- 官方市場(chǎng)雙十一精選推薦
- 技術(shù)人做產(chǎn)品有機(jī)會(huì)么(文末送課程)
- 本周秒殺——古德云售后獲客營(yíng)銷系統(tǒng)
- ThinkAPI服務(wù)更新——支持接口分組和PHP版本依賴調(diào)整
- PHP8新特性盤(pán)點(diǎn)
- PHP8新特性系列:構(gòu)造器屬性提升使用及注意事項(xiàng)
- ThinkPHP2021新年寄語(yǔ)
- ThinkPHP V6.0.6&V5.1.41版本發(fā)布——兼容PHP8.0
- PHP如何更優(yōu)雅地調(diào)用API接口
- ThinkPHP V6.0.7發(fā)布——修正版本
- ThinkAPI服務(wù)更新——IP白名單
- 最新版ThinkORM對(duì)于時(shí)間字段的調(diào)整
- ThinkAPI短信接口正式上線
- ThinkPHP V6.0.8版本發(fā)布——多環(huán)境變量配置支持
- 頂想云寫(xiě)作服務(wù)開(kāi)啟第一次公測(cè)
- ThinkSSL上線——官方SSL/TLS證書(shū)服務(wù)
- MDBootstrap國(guó)內(nèi)用戶福利——ThinkPHP官方市場(chǎng)首發(fā)
- ThinkPHP V6.0.9版本發(fā)布——常規(guī)更新
- ThinkORM功能盤(pán)點(diǎn)——虛擬模型
- 全面支持主流GIT版本庫(kù)——云寫(xiě)作服務(wù)第二次公測(cè)
- 云寫(xiě)作服務(wù)私有化部署方案之:版本庫(kù)私有化
- 看云雙十一活動(dòng)
- ThinkPHP V6.0.10LTS發(fā)布——兼容PHP8.1
- ThinkPHP V6.0.12發(fā)布——命令行兼容8.1
- 頂想云知識(shí)管理上線公測(cè)——構(gòu)建企業(yè)文檔中心和知識(shí)庫(kù)
- 頂想云上線——助力生態(tài)數(shù)字化建設(shè)
- 618活動(dòng)進(jìn)行中——官方市場(chǎng)迎來(lái)一波更新
- 頂想云知識(shí)管理正式上線——看云文檔啟動(dòng)遷移服務(wù)
- ThinkPHP V6.0.13發(fā)布——常規(guī)更新
- 頂想云網(wǎng)站助理服務(wù)上線——構(gòu)建產(chǎn)品支持服務(wù)
- ThinkPHP發(fā)布6.1.0&6.0.14版本——安全更新
- ThinkPHP新版社區(qū)上線試運(yùn)營(yíng)
- ThinkAPI上架人臉核身接口——助力網(wǎng)站實(shí)名認(rèn)證
- 辭舊迎新——舊版社區(qū)停止注冊(cè)及發(fā)帖
- ThinkPHP6.1.2版本發(fā)布——兼容PHP8.2
