我盡量遍歷寫一遍Illuminate\Database\Query\Builder類的大部分方法
select
設置查詢字段
Notice::select('title')->get();
Notice::select(['title', 'content'])->get();
selectRaw
查詢自定義內容
Notice::selectRaw("count('id') as notice_count")->get();
addSelect
如果您已經有一個查詢構建器實例,並且希望在其現有select子句中添加一列,則可以使用以下addSelect方法:
$query = DB::table('users')->select('name');
$users = $query->addSelect('age')->get();
distinct
該distinct方法允許您強制查詢返回不同的結果:
$users = DB::table('users')->distinct()->get();
from
設置表名屬性,table()方法也是通過這個方法設置
DB::table('users')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
上面的查詢其實就是with()方法的原理了,轉成sql如下
select * from users
where exists (
select 1 from orders where orders.user_id = users.id
)
這里補充一下模型關聯的方法
hasOne
public function user($class = User::class)
{
return $this->hasOne($class, 'id', 'user_id');
}
order表的user_id關聯user表的id,一對一,$class 可以作為參數,當user子類model關聯order子類model的時候,可以靈活重寫
public function user($class = User::class)
{
return $this->hasOne($class, 'id', 'user_id');
}
當你需要關聯最后一條記錄時
public function order($class = Order::class)
{
return $this->hasOne($class, 'user_id', 'id')->orderBy('id', 'desc');
}
where之類的條件拼接也是可行的
public function order($class = Order::class)
{
return $this->hasOne($class, 'user_id', 'id')->where('status', Order::STATUS_CREATE);
}
hasMany
public function orders($class = Order::class)
{
return $this->hasMany($class, 'user_id', 'id');
}
user表的id關聯order表的user_id,一對多
belongsTo
public function user($class = User::class)
{
return $this->belongsTo($class, 'user_id', 'id');
}
order表的user_id關聯user表的id,一對一
這里有人可能會問,這belongsTo和hasOne有啥區別
網上是這樣解釋的
hasOne(hasMany)使用在:外鍵在子關聯對象中,如業務上user表在order表之上,在User模型使用hasOne關聯order
class User{
public function order($class = Order::class)
{
return $this->hasOne($class, 'user_id', 'id');
}
}
belongsTo(belongsToMany)使用在:外鍵在父聯對象中,如業務上order表在user表之下,在Order模型使用belongsTo關聯user
class Order{
public function user($class = User::class)
{
return $this->belongsTo($class, 'user_id', 'id');
}
}
belongsToMany
public function roles()
{
return $this->belongsToMany(
\Common\Models\Rbac\Role::class,
'admin_has_roles',
'admin_id',
'role_id'
);
}
管理員表admin,角色表role,中間表為admin_has_roles,admin表可以通過中間表查出對應的角色集合
我們可以看出,這里的使用也印證了hasMany與belongsToMany的區別,belongsToMany是向上查詢的,必有一張admin_has_roles的中間表進行關聯
這樣描述可能有點抽象,我們可以假設上面的user和order的例子,
當一個order指向多個user時(比如多人拼單,只是假設),我們不可能在user表加order_id,所以下級業務表order在關聯上級業務表user時,必會有order_has_users之類的中間表,也會用到belongsToMany關聯,而不是hasMany了(暫時沒有更通俗的表述,有好的建議可以評論補充一下)
join
關聯查詢,join()方法最后還有兩個參數,$type和$where, $type是鏈表方式(inner,left,right,cross),$where是關聯條件(on,where)
后面的一些join方法(joinWhere,leftJoin,leftJoinWhere,rightJoin,rightJoinWhere,crossJoin)的實現是通過傳$type和$where調用join()來實現的
$users = DB::table('users')
->join('contacts', 'users.id', '=', 'contacts.user_id')
->join('orders', 'users.id', '=', 'orders.user_id')
->select('users.*', 'contacts.phone', 'orders.price')
->get();
cross join(笛卡爾積): mysql的交叉連接,數據分析和統計有時會用得上
cross join相關:https://www.yiibai.com/mysql/cross-join.html
joinWhere
join的時候,$where參數的on值換成了where值, 外鍵關聯換成條件
$users = DB::table('users')
->joinWhere('contacts', 'contacts.type', '=', '1')
->join('orders', 'users.id', '=', 'orders.user_id')
->select('users.*', 'contacts.phone', 'orders.price')
->get();
leftJoin
join的時候,$type參數的inner值換成了left值, 左匹配
$users = DB::table('users')
->leftJoin('posts', 'users.id', '=', 'posts.user_id')
->get();
leftJoinWhere
join的時候,
$type參數的inner值換成了left值, 左匹配
$where參數的on值換成了where值, 外鍵關聯換成條件
$users = DB::table('users')
->leftJoinWhere('posts', 'posts.type', '=', '1')
->get();
rightJoin
同理
rightJoinWhere
同理
crossJoin
同理
---------后面的暫時不一一寫了,先寫幾個常用的方法----------
where
為了使用方便,where方法提供了多種傳值方式, 最后有一個$boolean參數 默認and, 可傳or
$user = DB::table('users')->where('name', 'John')->first();
$user = DB::table('users')->where('name', '=', 'John')->first();
$user = DB::table('users')->where([['name', '=', 'John'], ['telephone', '=', '18812341234']])->first();
echo $user->name;
orWhere
$users = DB::table('users')
->where('votes', '>', 100)
->orWhere('name', 'John')
->get();
groupBy
可傳數組或多個參數
Notice::groupBy('title', 'id')->get();
Notice::groupBy(['title', 'id'])->get();
having
Notice::having('title', '=', '2')->get();
orHaving
Notice::having('title', '=', '2')->orHaving('title', '=', '1')->get();
havingRaw
$orders = DB::table('orders')
->select('department', DB::raw('SUM(price) as total_sales'))
->groupBy('department')
->havingRaw('SUM(price) > ?', [2500])
->get();
orHavingRaw
$orders = DB::table('orders')
->select('department', DB::raw('SUM(price) as total_sales'))
->groupBy('department')
->orHavingRaw('SUM(price) > ?', [2500])
->get();
orderBy
orderBy只能多個拼接
Notice::orderBy('title')->get();
Notice::orderBy('title')->orderBy('content')->get();
orderByDesc
Notice::orderByDesc('title')->get();
latest
public function latest($column = 'created_at')
{
return $this->orderBy($column, 'desc');
}
oldest
public function oldest($column = 'created_at')
{
return $this->orderBy($column, 'asc');
}
inRandomOrder
隨機排序法 可傳參,傳同樣參數會得到同樣的排列
Notice::inRandomOrder()->get(); Notice::inRandomOrder(1)->get();
orderByRaw
Notice::orderByRaw('title, content')->get();
find
注:從源碼上看find和findMary是通的,find第一個參數傳數組時,會調用findMany方法
Notice::find(1); Notice::find(1, ['title']); Notice::find([1,2], ['title']);
value
從查詢的第一個結果中獲取單個列的值
Notice::where('title', 1)->value('title');
get
查詢列,可指定查詢項get(['title', 'content']),
Notice::where('title', 1)->get();
注:該特別注意的是get查詢不到結果時返回的是一個空數組,不能直接用!判斷
paginate
返回指定查詢條數的數據,總條數,當前分頁之類的
DB::table('notice')->paginate();
simplePaginate 同上 返回參數有所刪減,數據量較大的查詢性能較高
cursor
數據量大時,用cursor做遍歷會節省很多內存
DB::table('notice')->get();
foreach (DB::table('notice')->cursor() as $notice){
var_dump($notice);
}
chunkById
分次查詢,第一個參數是每次查的條數,默認根據id查,如果需定制可在第三個參數傳
$noticeArr = [];
$notice = DB::table('notice')->chunkById(10, function($notices) use (&$noticeArr){
$noticeArr[] = json_decode(json_encode($notices, 256), true);
}, 'notice_id');
var_dump($notice);
var_dump($noticeArr);
exit();
該方法為分頁查詢,如果涉及更新,需慎用該方法
pluck
查詢某一個字段,返回該只有該字段的數組集合,第二個參數為指定某個參數為鍵,返回鍵值對集合
DB::table('roles')->pluck('title');
DB::table('roles')->pluck('title', 'name');
implode
根據查詢字段和符號分割
DB::table('notice')->implode('title', ',');//titlea,title2,titlec
exists
判斷查詢記錄是否存在
DB::table('notice')->where('status', 1)->exists();//true
DB::table('notice')->where('status', 'a')->exists();//false
doesntExist
同exists,返回結果和exists相反
DB::table('notice')->where('status', 1)->exists();//false
DB::table('notice')->where('status', 'a')->exists();//true
count
返回個數
DB::table('notice')->where('status', 1)->count();
min
最小
DB::table('notice')->min('notice_id');
max
最大
DB::table('notice')->max('notice_id');
sum
總和
DB::table('notice')->sum('notice_id');
avg
平均
DB::table('notice')->avg('notice_id');
average 同avg
aggregate
查詢生成器還提供了各種聚合方法,如計數、max、min、avg和和。您可以在構造查詢之后調用這些方法中的任何一種:
DB::table('notice')->aggregate('sum', ['notice_id']);
numericAggregate
方法調用aggregate,將結果轉數字
DB::table('notice')->numericAggregate('sum', ['notice_id']);
insert
插入 返回布爾值
Notice::insert(['title' => 'ad']); Notice::insert(['title' => 'ad', 'a' => 1]);
insertGetId
插入 返回id
Notice::insertGetId(['title' => 'ad']);
update
更新 返回布爾值
$notice = Notice::find(1); $notice->update(['title' => 'ad']);
updateOrInsert
更新或插入
Notice::updateOrInsert(['title' => 'ad'], ['content' => 'adcd']);
increment
加,字符串會被轉成0,然后加1
Notice::increment('title');//該字段加1
Notice::increment('title', 6);//該字段加6
decrement
加,字符串會被轉成0,然后1
Notice::decrement('title');//該字段減1
Notice::decrement('title', 6);//該字段減6
delete
刪除
$notice = Notice::find(1); return $notice->delete();
truncate
如果希望截斷整個表,該表將刪除所有行,並將自動遞增ID重置為零,則可以使用截斷方法:
DB::table('notice')->truncate();
newQuery
獲取查詢生成器的新實例。
$query = (new Notice())->newQuery(); return $query->find(1);
raw
若要創建原始表達式,可以使用Db::raw方法
DB::table('notice')->select(DB::raw('count(*) as notice_count'))->get();
__call
當方法不存在時,拋異常
public function __call($method, $parameters)
{
if (static::hasMacro($method)) {
return $this->macroCall($method, $parameters);
}
if (Str::startsWith($method, 'where')) {
return $this->dynamicWhere($method, $parameters);
}
$className = static::class;
throw new BadMethodCallException("Call to undefined method {$className}::{$method}()");
}
Illuminate\Database\Query\Builder 加載的代碼塊
Illuminate\Database\Concerns\BuildsQueries
chunk
如果你需要處理成千上萬個 Eloquent 結果,可以使用 chunk 命令。chunk 方法會獲取一個“組塊”的 Eloquent 模型,並將其填充到給定閉包進行處理。使用 chunk 方法能夠在處理大量數據集合時能夠有效減少內存消耗:
$noticeRes = [
'success' => 0,
'fail' => 0,
];
$notice = DB::table('notice')->orderBy('notice_id')->chunk(500, function ($notices) use (&$noticeRes) {
foreach ($notices as $notice) {
if($notice->status == 1){
$noticeRes['success']++;
}else{
$noticeRes['fail']++;
}
}
});
var_dump($notice);
var_dump($noticeRes);
exit();
each
在分組時對每個項執行回調,查詢結果為值(value),chunk方法需要循環,each方法內部做了循環
$noticeRes = [
'success' => 0,
'fail' => 0,
];
$notice = DB::table('notice')
->orderBy('id')
->each(function ($notice_value, $notice_key) use (&$noticeRes) {
if($notice_value->status){
$noticeRes['success']++;
}else{
$noticeRes['fail']++;
}
}, 500);
var_dump($notice);
var_dump($noticeRes);
exit();
下面是Illuminate\Database\Eloquent\Builder類的大部分方法
fromQuery
應該只有復雜查詢要寫原生的時候才會用到
Notice::fromQuery("select title from notice");
Notice::fromQuery('select title from notice WHERE title = ?', [1]);
findMany
Notice::findMany([1,2], ['title']); Notice::findMany(1, ['title']);
findOrFail
這個查不到會直接拋出ModelNotFoundException異常,可以在App\Exceptions\Handler定制異常捕捉
Notice::findOrFail(100);
findOrNew
這個查不到會通過newModelInstance方法新建一個模型對象
Notice::findOrNew(100);
firstOrNew
這個查不到會通過newModelInstance方法新建一個模型對象,並把參數一(array)$attributes {array}$values 合為一個數組賦給模型
Notice::firstOrNew(['title' => 14]); Notice::firstOrNew(['title' => 100], ['content' => 123]);
newModelInstance
這個方法在比較后,因為前面有用到,所以先講下
創建模型,根據傳入的數組賦值
Notice::newModelInstance(['title' => 100, 'content' => 123]);
firstOrCreate
查詢或新建一條記錄,第一個參數為查詢條件,如果找不到,會把參數一(array)$attributes {array}$values 合為一個數組賦值,新建一條記錄並返回模型
Notice::firstOrCreate(['title' => 14], ['content' => 123]);
updateOrCreate
更新或新建一條記錄,第一個參數為查詢條件,找到則把第二個參數的值賦給查到的model,如果找不到,會先執行firstOrNew($attributes)方法,創建對象,然后把{array}$values通過fill($values)賦值再執行save()保存
Notice::UpdateOrCreate(['title' => 14], ['content' => 1234]);
源碼:
/**
* Create or update a record matching the attributes, and fill it with values.
*
* @param array $attributes
* @param array $values
* @return \Illuminate\Database\Eloquent\Model
*/
public function updateOrCreate(array $attributes, array $values = [])
{
return tap($this->firstOrNew($attributes), function ($instance) use ($values) {
$instance->fill($values)->save();
});
}
注:tap是laravel內置的一個方法,簡單實用 https://segmentfault.com/a/1190000008447747
function tap($value, $callback)
{
$callback($value);
return $value;
}
firstOrFail
查到返回對象,否則拋ModelNotFoundException異常
Notice::firstOrFail();
Notice::where('title', 321)->firstOrFail();
firstOr
查詢一條,不存在則執行自定義$callback方法,
firstOr($columns = ['*'], Closure $callback = null)
$callback可以在參數一或參數二傳,方法有對第一個參數做實現Closure類的判斷
$title = 1;
return Notice::where('title', 100)->firstOr(function() use ($title) {
return Notice::UpdateOrCreate(['title' => $title], ['content' => 1234]);
});
with
表關聯查詢
model
class Notice{
public function uploadRelation()
{
return $this->hasMany(UploadRelation::class, 'relation_id', 'id')
->where('relation_type', '=', UploadRelation::RELATION_TYPE_NOTICE)
->select('relation_type','relation_id', 'upload_id');
}
}
class UploadRelation{
public function upload()
{
return $this->hasOne(Upload::class, 'id', 'upload_id');
}
}
調用關聯
Notice::with('uploadRelation')->get();
Notice::with('uploadRelation.upload')->get();
Notice::with([
'uploadRelation' => function($query){
$query->select('relation_id', 'upload_id');
}
])->get();
Notice::with([
'uploadRelation' => function($query){
$query->select('relation_id', 'upload_id')->with([
'upload' => function($query){
$query->select('id', 'path');
}
]);
}
])->get();
without
用來注銷綁定
Notice::with('uploadRelation')->get();
Notice::with('uploadRelation')->without('uploadRelation')->get();
withCount
只獲取關聯條數
Notice::withCount('uploadRelation')->get();
null
->whereNotNull('updated_at');
->whereNull('updated_at');
實用:
數據庫:查詢生成器(Database: Query Builder):https://laravel.com/docs/5.6/queries
Laravel API Builder:https://laravel.com/api/5.3/Illuminate/Database/Eloquent/Builder.html
高級Join方法
如果join方法的約束條件比較復雜,可以使用閉包函數的方式指定
DB::table('users')
->join('contacts', function ($join) {
$join->on('users.id', '=', 'contacts.user_id')->orOn(...);
})
->get();
如果join約束中要使用列值與指定數組比較,則可以使用where和OrWhere方法
DB::table('users')
->join('contacts', function ($join) {
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.user_id', '>', 5);
})
->get();
高級join:https://segmentfault.com/a/1190000005792605
轉載自:
Lumen 數據庫操作orm:https://www.jianshu.com/p/492e1cb1eb28
Lumen 數據庫操作orm之表關聯hasOne(hasMany)和belongsTo(belongsToMany):https://www.jianshu.com/p/d11e5f84a699
