鍍金池/ 教程/ PHP/ 查詢構(gòu)建器
門面
Laravel Homestead
安裝及配置
測試
HTTP 中間件
加密
升級指南
幫助函數(shù)
應(yīng)用目錄結(jié)構(gòu)
集合
新手入門指南-簡單任務(wù)管理系統(tǒng)
任務(wù)調(diào)度
查詢構(gòu)建器
視圖
驗(yàn)證
Laravel Cashier(訂購&支付&發(fā)票)
本地化
隊(duì)列
調(diào)整器
分頁
文件系統(tǒng)/云存儲
貢獻(xiàn)代碼
哈希
HTTP 控制器
緩存
遷移
HTTP 請求
Laravel Elixir
發(fā)行版本說明
Envoy 任務(wù)運(yùn)行器(SSH任務(wù))
序列化
Session
起步
帶用戶功能的任務(wù)管理系統(tǒng)
起步
用戶授權(quán)
郵件
事件
填充數(shù)據(jù)
HTTP 路由
服務(wù)提供者
Blade 模板引擎
包開發(fā)
用戶認(rèn)證
Artisan 控制臺
HTTP 響應(yīng)
集合
服務(wù)容器
關(guān)聯(lián)關(guān)系
一次請求的生命周期
契約
Redis
錯(cuò)誤&日志

查詢構(gòu)建器

1、簡介

數(shù)據(jù)庫查詢構(gòu)建器提供了一個(gè)方便的、平滑的接口來創(chuàng)建和運(yùn)行數(shù)據(jù)庫查詢。查詢構(gòu)建器可以用于執(zhí)行應(yīng)用中大部分?jǐn)?shù)據(jù)庫操作,并且能夠在支持的所有數(shù)據(jù)庫系統(tǒng)上工作。 注意:Laravel 查詢構(gòu)建器使用 PDO 參數(shù)綁定來避免 SQL 注入攻擊,不再需要清除傳遞到綁定的字符串。

2、獲取結(jié)果集

2.1 從一張表中取出所有行

在查詢之前,使用 DB 門面的 table 方法,table 方法為給定表返回一個(gè)查詢構(gòu)建器,允許你在查詢上鏈接更多約束條件并最終返回查詢結(jié)果。在本例中,我們使用 get 方法獲取表中所有記錄:

<?php

namespace App\Http\Controllers;

use DB;
use App\Http\Controllers\Controller;

class UserController extends Controller{
    /**
     * 顯示用戶列表
     *
     * @return Response
     */
    public function index()
    {
        $users = DB::table('users')->get();

        return view('user.index', ['users' => $users]);
    }
}

和原生查詢一樣,get 方法返回結(jié)果集的數(shù)據(jù)組,其中每一個(gè)結(jié)果都是 PHP 對象的 StdClass 實(shí)例。你可以像訪問對象的屬性一樣訪問列的值:

foreach ($users as $user) {
    echo $user->name;
}

2.2 從一張表中獲取一行/一列

如果你只是想要從數(shù)據(jù)表中獲取一行數(shù)據(jù),可以使用 first 方法,該方法將會(huì)返回單個(gè) StdClass 對象:

$user = DB::table('users')->where('name', 'John')->first();
echo $user->name;

2.3 從一張表中獲取組塊結(jié)果集

如果你需要處理成千上百條數(shù)據(jù)庫記錄,可以考慮使用 chunk方法,該方法一次獲取結(jié)果集的一小塊,然后填充每一小塊數(shù)據(jù)到要處理的閉包,該方法在編寫處理大量數(shù)據(jù)庫記錄的 Artisan 命令的時(shí)候非常有用。比如,我們可以將處理全部 users 表數(shù)據(jù)處理成一次處理 100 記錄的小組塊:

DB::table('users')->chunk(100, function($users) {
    foreach ($users as $user) {
        //
    }
});

你可以通過從閉包函數(shù)中返回 false 來中止組塊的運(yùn)行:

DB::table('users')->chunk(100, function($users) {
    // 處理結(jié)果集...
    return false;
});

2.4 獲取數(shù)據(jù)列值列表

如果想要獲取包含單個(gè)列值的數(shù)組,可以使用 lists 方法,在本例中,我們獲取所有title 的數(shù)組:

$titles = DB::table('roles')->lists('title');

foreach ($titles as $title) {
    echo $title;
}

在還可以在返回?cái)?shù)組中指定更多的自定義鍵:

$roles = DB::table('roles')->lists('title', 'name');

foreach ($roles as $name => $title) {
    echo $title;
}

2.5 聚合函數(shù)

隊(duì)列構(gòu)建器還提供了很多聚合方法,比如 count, max, min, avg, 和 sum,你可以在構(gòu)造查詢之后調(diào)用這些方法:

$users = DB::table('users')->count();$price = DB::table('orders')->max('price');

當(dāng)然,你可以聯(lián)合其它查詢字句和聚合函數(shù)來構(gòu)建查詢:

$price = DB::table('orders')
                ->where('finalized', 1)
                ->avg('price');

3、查詢(Select)

3.1 指定查詢子句

當(dāng)然,我們并不總是想要獲取數(shù)據(jù)表的所有列,使用 select 方法,你可以為查詢指定自定義的 select 子句:

$users = DB::table('users')->select('name', 'email as user_email')->get();

distinct方法允許你強(qiáng)制查詢返回不重復(fù)的結(jié)果集:

$users = DB::table('users')->distinct()->get();

如果你已經(jīng)有了一個(gè)查詢構(gòu)建器實(shí)例并且希望添加一個(gè)查詢列到已存在的 select 子句,可以使用 addSelect 方法:

$query = DB::table('users')->select('name');
$users = $query->addSelect('age')->get();

3.2 原生表達(dá)式

有時(shí)候你希望在查詢中使用原生表達(dá)式,這些表達(dá)式將會(huì)以字符串的形式注入到查詢中,所以要格外小心避免被 SQL 注入。想要?jiǎng)?chuàng)建一個(gè)原生表達(dá)式,可以使用 DB::raw 方法:

$users = DB::table('users')
                     ->select(DB::raw('count(*) as user_count, status'))
                     ->where('status', '<>', 1)
                     ->groupBy('status')
                     ->get();

4、連接(Join)

4.1 內(nèi)連接(等值連接)

查詢構(gòu)建器還可以用于編寫基本的 SQL“內(nèi)連接”,你可以使用查詢構(gòu)建器實(shí)例上的 join 方法,傳遞給 join 方法的第一次參數(shù)是你需要連接到的表名,剩余的其它參數(shù)則是為連接指定的列約束,當(dāng)然,正如你所看到的,你可以在單個(gè)查詢中連接多張表:

$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();

4.2 左連接

如果你是想要執(zhí)行“左連接”而不是“內(nèi)連接”,可以使用 leftJoin 方法。該方法和 join 方法的使用方法一樣:

$users = DB::table('users')
            ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
            ->get();

4.3 高級連接語句

你還可以指定更多的高級連接子句,傳遞一個(gè)閉包到 join 方法作為該方法的第 2 個(gè)參數(shù),該閉包將會(huì)返回允許你指定 join 子句約束的 JoinClause 對象:

DB::table('users')
        ->join('contacts', function ($join) {
            $join->on('users.id', '=', 'contacts.user_id')->orOn(...);
        })
        ->get();

如果你想要在連接中使用“where”風(fēng)格的子句,可以在查詢中使用 whereorWhere 方法。這些方法將會(huì)將列和值進(jìn)行比較而不是列和列進(jìn)行比較:

DB::table('users')
        ->join('contacts', function ($join) {
            $join->on('users.id', '=', 'contacts.user_id')
                 ->where('contacts.user_id', '>', 5);
        })
        ->get();

5、聯(lián)合(Union)

查詢構(gòu)建器還提供了一條“聯(lián)合”兩個(gè)查詢的快捷方式,比如,你要?jiǎng)?chuàng)建一個(gè)獨(dú)立的查詢,然后使用 union 方法將其和第二個(gè)查詢進(jìn)行聯(lián)合:

$first = DB::table('users')
            ->whereNull('first_name');

$users = DB::table('users')
            ->whereNull('last_name')
            ->union($first)
            ->get();

unionAll 方法也是有效的,并且和 union 有同樣的使用方法。

6、Where 子句

6.1 簡單 where 子句

使用查詢構(gòu)建器上的 where 方法可以添加 where 子句到查詢中,調(diào)用 where 最基本的方法需要三個(gè)參數(shù),第一個(gè)參數(shù)是列名,第二個(gè)參數(shù)是一個(gè)數(shù)據(jù)庫系統(tǒng)支持的任意操作符,第三個(gè)參數(shù)是該列要比較的值。 例如,下面是一個(gè)驗(yàn)證“votes”列的值是否等于 100 的查詢:

$users = DB::table('users')->where('votes', '=', 100)->get();

為了方便,如果你只是簡單比較列值和給定數(shù)值是否相等,可以將數(shù)值直接作為 where 方法的第二個(gè)參數(shù):

$users = DB::table('users')->where('votes', 100)->get();

當(dāng)然,你可以使用其它操作符來編寫 where 子句:

$users = DB::table('users')
                ->where('votes', '>=', 100)
                ->get();

$users = DB::table('users')
                ->where('votes', '<>', 100)
                ->get();

$users = DB::table('users')
                ->where('name', 'like', 'T%')
                ->get();

6.2 or 你可以通過方法鏈將多個(gè) where 約束鏈接到一起,也可以添加 or 子句到查詢,orWhere 方法和 where 方法接收參數(shù)一樣:

$users = DB::table('users')
                    ->where('votes', '>', 100)
                    ->orWhere('name', 'John')
                    ->get();

6.3 更多 Where 子句

6.3.1 whereBetween

whereBetween 方法驗(yàn)證列值是否在給定值之間:

$users = DB::table('users')
                    ->whereBetween('votes', [1, 100])->get();

6.3.2 whereNotBetween

whereNotBetween方法驗(yàn)證列值不在給定值之間:

$users = DB::table('users')
                    ->whereNotBetween('votes', [1, 100])
                    ->get();

6.3.3 whereIn/whereNotIn

whereIn 方法驗(yàn)證給定列的值是否在給定數(shù)組中:

$users = DB::table('users')
                    ->whereIn('id', [1, 2, 3])
                    ->get();

whereNotIn 方法驗(yàn)證給定列的值不在給定數(shù)組中:

$users = DB::table('users')
                    ->whereNotIn('id', [1, 2, 3])
                    ->get();

6.3.4 whereNull/whereNotNull whereNull方法驗(yàn)證給定列的值為 NULL:

$users = DB::table('users')
                    ->whereNull('updated_at')
                    ->get();

whereNotNull 方法驗(yàn)證給定列的值不是 NULL:

$users = DB::table('users')
                    ->whereNotNull('updated_at')
                    ->get();

6.4 高級 Where 子句

6.4.1 參數(shù)分組

有時(shí)候你需要?jiǎng)?chuàng)建更加高級的 where 子句比如”where exists“或者嵌套的參數(shù)分組。Laravel 查詢構(gòu)建器也可以處理這些。作為開始,讓我們看一個(gè)在括號中進(jìn)行分組約束的例子:

DB::table('users')
            ->where('name', '=', 'John')
            ->orWhere(function ($query) {
                $query->where('votes', '>', 100)
                      ->where('title', '<>', 'Admin');
            })
            ->get();

正如你所看到的,傳遞閉包到 orWhere 方法構(gòu)造查詢構(gòu)建器來開始一個(gè)約束分組,,該閉包將會(huì)獲取一個(gè)用于設(shè)置括號中包含的約束的查詢構(gòu)建器實(shí)例。上述語句等價(jià)于下面的 SQL:

select * from users where name = 'John' or (votes > 100 and title <> 'Admin')

6.4.2 exists 語句

whereExists 方法允許你編寫 where existSQL 子句,whereExists 方法接收一個(gè)閉包參數(shù),該閉包獲取一個(gè)查詢構(gòu)建器實(shí)例從而允許你定義放置在”exists”子句中的查詢:

DB::table('users')
            ->whereExists(function ($query) {
                $query->select(DB::raw(1))
                      ->from('orders')
                      ->whereRaw('orders.user_id = users.id');
            })
            ->get();

上述查詢等價(jià)于下面的 SQL 語句:

select * from users
where exists (
    select 1 from orders where orders.user_id = users.id
)

7、排序、分組、限定

7.1 orderBy

orderBy方法允許你通過給定列對結(jié)果集進(jìn)行排序,orderBy 的第一個(gè)參數(shù)應(yīng)該是你希望排序的列,第二個(gè)參數(shù)控制著排序的方向——asc 或 desc:

$users = DB::table('users')
                ->orderBy('name', 'desc')
                ->get();

7.2 groupBy / having / havingRaw

groupByhaving方法用于對結(jié)果集進(jìn)行分組,having 方法和 where方法的用法類似:

$users = DB::table('users')
                ->groupBy('account_id')
                ->having('account_id', '>', 100)
                ->get();

havingRaw方法可以用于設(shè)置原生字符串作為 having子句的值,例如,我們要找到所有售價(jià)大于$2500的部分:

$users = DB::table('orders')
                ->select('department', DB::raw('SUM(price) as total_sales'))
                ->groupBy('department')
                ->havingRaw('SUM(price) > 2500')
                ->get();

7.3 skip / take

想要限定查詢返回的結(jié)果集的數(shù)目,或者在查詢中跳過給定數(shù)目的結(jié)果,可以使用 skiptake 方法:

$users = DB::table('users')->skip(10)->take(5)->get();

8、插入(Insert)

查詢構(gòu)建器還提供了 insert方法來插入記錄到數(shù)據(jù)表。insert 方法接收數(shù)組形式的列名和值進(jìn)行插入操作:

DB::table('users')->insert(
    ['email' => 'john@example.com', 'votes' => 0]);

你甚至可以一次性通過傳入多個(gè)數(shù)組來插入多條記錄,每個(gè)數(shù)組代表要插入數(shù)據(jù)表的記錄:

DB::table('users')->insert([
    ['email' => 'taylor@example.com', 'votes' => 0],
    ['email' => 'dayle@example.com', 'votes' => 0]
]);

8.1 自增 ID

如果數(shù)據(jù)表有自增 ID,使用 insertGetId方法來插入記錄將會(huì)返回 ID 值:

$id = DB::table('users')->insertGetId(
    ['email' => 'john@example.com', 'votes' => 0]
);

注意:當(dāng)使用 PostgresSQL 時(shí) insertGetId 方法默認(rèn)自增列被命名為 id,如果你想要從其他”序列“獲取 ID,可以將序列名作為第二個(gè)參數(shù)傳遞到 insertGetId 方法。

9、更新(Update)

當(dāng)然,除了插入記錄到數(shù)據(jù)庫,查詢構(gòu)建器還可以通過使用update 方法更新已有記錄。update 方法和insert 方法一樣,接收列和值的鍵值對數(shù)組包含要更新的列,你可以通過 where子句來對update 查詢進(jìn)行約束:

DB::table('users')
            ->where('id', 1)
            ->update(['votes' => 1]);

9.1 增加/減少

查詢構(gòu)建器還提供了方便增減給定列名數(shù)值的方法。相較于編寫 update 語句,這是一條捷徑,提供了更好的體驗(yàn)和測試接口。 這兩個(gè)方法都至少接收一個(gè)參數(shù):需要修改的列。第二個(gè)參數(shù)是可選的,用于控制列值增加/減少的數(shù)目。

DB::table('users')->increment('votes');
DB::table('users')->increment('votes', 5);
DB::table('users')->decrement('votes');
DB::table('users')->decrement('votes', 5);

在操作過程中你還可以指定額外的列進(jìn)行更新:

DB::table('users')->increment('votes', 1, ['name' => 'John']);

10、刪除(Delete)

當(dāng)然,查詢構(gòu)建器還可以通過 delete 方法從表中刪除記錄:

DB::table('users')->delete();

在調(diào)用 delete 方法之前可以通過添加 where 子句對 delete 語句進(jìn)行約束:

DB::table('users')->where('votes', '<', 100)->delete();

如果你希望清除整張表,也就是刪除所有列并將自增 ID 置為 0,可以使用 truncate 方法:

DB::table('users')->truncate();

11、悲觀鎖

查詢構(gòu)建器還包含一些方法幫助你在 select 語句中實(shí)現(xiàn)”悲觀鎖“??梢栽诓樵冎惺褂?sharedLock 方法從而在運(yùn)行語句時(shí)帶一把”共享鎖“。共享鎖可以避免被選擇的行被修改直到事務(wù)提交:

DB::table('users')->where('votes', '>', 100)->sharedLock()->get();

此外你還可以使用 lockForUpdate 方法?!眆or update“鎖避免選擇行被其它共享鎖修改或刪除:

DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get();
上一篇:安裝及配置下一篇:幫助函數(shù)