天天看點

ThinkPHP5.1學習筆記 資料庫操作

資料庫

參見《Thinkphp5.1完全開發手冊》學習

Mirror王宇陽

資料庫連接配接

  • ThinkPHP采用内置抽象層對資料庫操作進行封裝處理;且基于PDO模式,可以适配各種資料庫。
  • 資料庫連接配接的配置檔案(config/database.php)設定資料庫的連接配接資訊
    class DataTest extends Controller// 資料庫連接配接
    { // url => http://localhost/tp5.1/public/index.php/index/data_test
        public function index()
        {
            $data = Db::table(\'tp_access\')->select();
            $data = Db::name(\'access\')->select();
            return json($data);
    
        }
    }
               

查詢控制器(資料庫操作)

想要檢視SQL的執行語句細節可以配置:config/app.php -> app_trace => true;

開啟後就可以在HTML頁面右下角打開SQL語句的具體執行過程

注意:json輸出的資料無法使用這一功能哦!

查詢資料

查詢單個資料使用

find

方法:

// table方法必須指定完整的資料表名
Db::table(\'think_user\')->where(\'id\',1)->find();
           

最終生成的SQL語句可能是:

SELECT * FROM `think_user` WHERE  `id` = 1 LIMIT 1
           
find 方法查詢結果不存在,傳回 null,否則傳回結果數組

V5.1.23+

版本開始,支援

findOrEmpty

方法,當查詢不存在的時候傳回空數組而不是Null。

// table方法必須指定完整的資料表名
Db::table(\'think_user\')->where(\'id\',1)->findOrEmpty();
           

如果沒有查找到資料,則會抛出一個

think\db\exception\DataNotFoundException

異常。

try{ //捕獲異常
    // table方法必須指定完整的資料表名
    $data = Db::table(\'think_user\')->where(\'id\',1)->findOrEmpty();
} catch (DataNotFoundException $err) {
    return \'資料查詢發送異常!\'
}
           

查詢多個資料(資料集)使用

select

方法:

Db::table(\'think_user\')->where(\'status\',1)->select();
           

最終生成的SQL語句可能是:

SELECT * FROM `think_user` WHERE `status` = 1
           
select 方法查詢結果是一個二維數組,如果結果不存在,傳回空數組

如果希望在沒有查找到資料後抛出異常可以使用

try{ //捕獲異常
    $data = Db::table(\'think_user\')->where(\'status\',1)->selectOrFail();
} catch (DataNotFoundException $err) {
    return \'資料查詢發送異常!\'
}
           
預設情況下,

find

select

方法傳回的都是數組,差別在于後者是二維數組。

系統提供了一個

db

助手函數,可以更友善的查詢:

db(\'user\')->where(\'id\',1)->find();
db(\'user\')->where(\'status\',1)->select();
           

db

方法的第一個參數的作用和

name

方法一樣,如果需要使用不同的資料庫連接配接,可以使用:

db(\'user\',\'db_config1\')->where(\'id\', 1)->find();
           

查詢某個字段的值可以用 value(‘字段名’)

// 傳回某個字段的值
Db::table(\'think_user\')->where(\'id\',1)->value(\'name\');	
           
value 方法查詢結果不存在,傳回 null

查詢某一列的值可以用 colum(\'字段名/列名\')

// 傳回數組
Db::table(\'think_user\')->where(\'status\',1)->column(\'name\');
// 指定id字段的值作為索引
Db::table(\'think_user\')->where(\'status\',1)->column(\'name\',\'id\');
           

如果要傳回完整資料,并且添加一個索引值的話,可以使用

// 指定id字段的值作為索引 傳回所有資料
Db::table(\'think_user\')->where(\'status\',1)->column(\'*\',\'id\');
           
column 方法查詢結果不存在,傳回空數組

資料分批處理可以使用 chunk

我們可以全部使用者表資料進行分批處理,每次處理 100 個使用者記錄:

Db::table(\'think_user\')->chunk(100, function($users) {
    foreach ($users as $user) {
        //
    }
});
// 或者交給回調方法myUserIterator處理
Db::table(\'think_user\')->chunk(100, \'myUserIterator\');
           

你可以通過從閉包函數中傳回

false

來中止對後續資料集的處理:

Db::table(\'think_user\')->chunk(100, function($users) {
    foreach ($users as $user) {
        // 處理結果集...
		if($user->status==0){
            return false;
        }
    }
});
           

也支援在

chunk

方法之前調用其它的查詢方法,例如:

Db::table(\'think_user\')
->where(\'score\',\'>\',80)
->chunk(100, function($users) {
    foreach ($users as $user) {
        //
    }
});
           

chunk

方法的處理預設是根據主鍵查詢,支援指定字段,例如:

Db::table(\'think_user\')->chunk(100, function($users) {
    // 處理結果集...
    return false;
},\'create_time\');
           

并且支援指定處理資料的順序。

Db::table(\'think_user\')->chunk(100, function($users) {
    // 處理結果集...
    return false;
},\'create_time\', \'desc\');
           

chunk

方法一般用于指令行操作批處理資料庫的資料,不适合WEB通路處理大量資料,很容易導緻逾時。

大批量資料處理

如果你需要處理大量的資料,可以使用新版提供的遊标查詢功能,該查詢方式利用了PHP的生成器特性,可以大幅減少大量資料查詢的記憶體占用問題。

$cursor = Db::table(\'user\')->where(\'status\', 1)->cursor();
foreach($cursor as $user){
	echo $user[\'name\'];
}
           

cursor

方法傳回的是一個生成器對象,

user

變量是資料表的一條資料(數組)。

JSON類型資料查詢(

mysql

// 查詢JSON類型字段 (info字段為json類型)
Db::table(\'think_user\')
	->where(\'info->email\',\'[email protected]\')
	->find();
           
鍊式查詢簡單認識
  • 查詢規則
    • 通過指向符号

      ->

      多次連續的調用方法
      Db::table(\'think_user\')
          ->where(\'status\',1)
          ->order(\'create_time\')
          ->limit(10)
          ->select();
                 
    • 多次i的調用使用傳回的都是資料庫對象,可以多次的鍊式查詢資料對象的方法
    • 最後的資料庫對象可以使用 find()、select() 等結果方法,傳回資料結果
    • find()、select()、value()、column() 是結果查詢方法,并不是鍊式查詢方法
  • 鍊式查詢方法:

    系統支援的鍊式操作方法包含:

    連貫操作 作用 支援的參數類型
    where* 用于AND查詢 字元串、數組和對象
    whereOr* 用于OR查詢 字元串、數組和對象
    wheretime* 用于時間日期的快捷查詢 字元串
    table 用于定義要操作的資料表名稱 字元串和數組
    alias 用于給目前資料表定義别名 字元串
    field* 用于定義要查詢的字段(支援字段排除) 字元串和數組
    order* 用于對結果排序 字元串和數組
    limit 用于限制查詢結果數量 字元串和數字
    page 用于查詢分頁(内部會轉換成limit) 字元串和數字
    group 用于對查詢的group支援 字元串
    having 用于對查詢的having支援 字元串
    join* 用于對查詢的join支援 字元串和數組
    union* 用于對查詢的union支援 字元串、數組和對象
    view* 用于視圖查詢 字元串、數組
    distinct 用于查詢的distinct支援 布爾值
    lock 用于資料庫的鎖機制 布爾值
    cache 用于查詢緩存 支援多個參數
    relation* 用于關聯查詢 字元串
    with* 用于關聯預載入 字元串、數組
    bind* 用于資料綁定操作 數組或多個參數
    comment 用于SQL注釋 字元串
    force 用于資料集的強制索引 字元串
    master 用于設定主伺服器讀取資料 布爾值
    strict 用于設定是否嚴格檢測字段名是否存在 布爾值
    sequence 用于設定Pgsql的自增序列名 字元串
    failException 用于設定沒有查詢到資料是否抛出異常 布爾值
    partition 用于設定分表資訊 數組 字元串
    所有的連貫操作都傳回目前的模型執行個體對象(this),其中帶*辨別的表示支援多次調用。
  • 更多查詢

    多次查詢并不需要每次都建立一個執行個體;可以儲存執行個體對象進行反複調用:

    $user = Db::name(\'user\');
    $data = $user->select();
               
    public function getModelData()
        {
            $book = Db::table(\'tp_book\');     // 建立tp_book的執行個體并保持$book
            $data = $book->select();
            return json($data);
            $data1 = $book->where(\'id\',1)->column(\'title\');
            //使用被保持的執行個體
            return json($data1); // 結果傳回 莎士比亞
            $data2 = $book->column(\'title\');
            // 被儲存的執行個體會保留上一個查詢結果(對象)
            return json($data3); // 結果傳回 與 $data2 一緻
        }
               
    執行個體會儲存上一個查詢對象結果,但使用

    removerOption()

    方法可以清理上一個保留的值
    $data3 = $book->removeOption(\'where\')->column(\'title\');
    return json($data3); // 結果傳回 沒有where條件限制了
               
增删改操作

新增資料

ThinkPHP5.1使用

insert()

insertGetId()

方法向資料表添加一條資料

使用

Db

類的

insert

方法向資料庫送出資料

$data = [\'foo\' => \'bar\', \'bar\' => \'foo\'];
// 筆者在insert()的時候,發現中文内容添加後會在資料庫中顯示空白
Db::name(\'user\')->insert($data);
           

insert

方法添加資料成功傳回添加成功的條數,通常情況傳回 1
// 新增資料到資料表中
    public function insert()
    {
        $book = Db::table(\'tp_book\');
        // 比對添加資料
        $data = [ // 可為空Null的、自動增補的可以忽略不添加
            \'user_id\'    =>  \'66\',
            \'title\'      =>  \'Mirror\'
        ];

        $book->insert($data);

        $select = $book->select();
        return json($select);
    }
           

或者使用

data

方法配合

insert

使用。

$data = [\'foo\' => \'bar\', \'bar\' => \'foo\'];
Db::name(\'user\')
    ->data($data)
    ->insert();
           
如果你的資料表裡面沒有

foo

或者

bar

字段,那麼就會抛出異常。

如果不希望抛出異常,可以使用下面的方法:

$data = [\'foo\' => \'bar\', \'bar\' => \'foo\'];
Db::name(\'user\')->strict(false)->insert($data);
           

不存在的字段的值将會直接抛棄。

如果是mysql資料庫,支援

replace

寫入,例如:

$data = [\'foo\' => \'bar\', \'bar\' => \'foo\'];
Db::name(\'user\')->insert($data, true);
           

添加資料後如果需要傳回新增資料的自增主鍵,可以使用

insertGetId

方法新增資料并傳回主鍵值:

$userId = Db::name(\'user\')->insertGetId($data);
           

insertGetId

方法添加資料成功傳回添加資料的自增主鍵

添加多條資料直接向 Db 類的

insertAll

方法傳入需要添加的資料即可

public  function insertAll()//批量添加到資料表
    {
        $dataAll = [
            [
                \'user_id\'    =>  \'66\',
                \'title\'      =>  \'《白帽子講Web安全》\'
            ],
            [
                \'user_id\'   => \'88\',
                \'title\'     => \'《喬布斯傳》\'
            ],
            [
                \'user_id\'   => \'99\',
                \'title\'     => \'《白夜行》\'
            ],
        ];


        $kk = Db::table(\'tp_book\')->insertAll($dataAll);
        return $kk;
    }
           
insertAll 方法添加資料成功傳回添加成功的條數

如果批量插入的資料比較多,可以指定分批插入,使用

limit

方法指定每次插入的數量限制。

$data = [
    [\'foo\' => \'bar\', \'bar\' => \'foo\'],
    [\'foo\' => \'bar1\', \'bar\' => \'foo1\'],
    [\'foo\' => \'bar2\', \'bar\' => \'foo2\']
    ...
];
// 分批寫入 每次最多100條資料
Db::name(\'user\')->data($data)->limit(100)->insertAll();
           

修改資料

// 修改資料
    public function update()
    {
        $date = [
            \'title\'     =>  \'《解憂雜貨鋪》\'
        ];

        $kk = Db::table(\'tp_book\')->where(\'user_id\',\'99\')->update($date);
        return $kk;
    }
           
update 方法傳回影響資料的條數,沒修改任何資料傳回 0

如果資料中包含主鍵,可以直接使用:

Db::name(\'user\')
    ->update([\'name\' => \'thinkphp\',\'id\'=>1]);
           

如果要更新的資料需要使用

SQL

函數或者其它字段,可以使用下面的方式:

Db::name(\'user\')
    ->where(\'id\',1)
    ->inc(\'read_time\') //對字段增值
    ->dec(\'score\',3) //對字段減值
    ->exp(\'name\',\'UPPER(name)\') // 在字段中使用mysql函數
    ->update();
           

可以使用

setInc/setDec

方法自增或自減一個字段的值( 如不加第二個參數,預設步長為1)。

// score 字段加 1
Db::table(\'think_user\')
    ->where(\'id\', 1)
    ->setInc(\'score\');
// score 字段加 5
Db::table(\'think_user\')
    ->where(\'id\', 1)
    ->setInc(\'score\', 5);
// score 字段減 1
Db::table(\'think_user\')
    ->where(\'id\', 1)
    ->setDec(\'score\');
// score 字段減 5
Db::table(\'think_user\')
    ->where(\'id\', 1)
    ->setDec(\'score\', 5);
           

setInc/setDec

支援延時更新,如果需要延時更新則傳入第三個參數,下例中延時10秒更新。

Db::name(\'user\')->where(\'id\', 1)->setInc(\'score\', 1, 10);
           

V5.1.7+

版本以後,支援使用

raw

方法進行資料更新,适合在數組更新的情況。

Db::name(\'user\')
    ->where(\'id\', 1)
    ->update([
        \'name\'		=>	Db::raw(\'UPPER(name)\'),
        \'score\'		=>	Db::raw(\'score-3\'),
        \'read_time\'	=>	Db::raw(\'read_time+1\')
    ]);
           

字段值更新 setField(\'原字段名\',\'新字段名\')

Db::name(\'user\')
    ->where(\'id\',1)
    ->setField(\'name\', \'thinkphp\');
           

删除資料

// 根據主鍵删除
Db::table(\'think_user\')->delete(1);
Db::table(\'think_user\')->delete([1,2,3]);

// 條件删除    
Db::table(\'think_user\')->where(\'id\',1)->delete();
Db::table(\'think_user\')->where(\'id\',\'<\',10)->delete();

// 無條件删除所有資料
Db::name(\'user\')->delete(true);

           
查詢表達式

比較查詢

Db::name(\'book\')->where(\'id\',80)->find();  		//簡寫
Db::name(\'book\')->where(\'id\',\'=\',80)->find();   //完整;且與第一條同意義 
           

5.1

還支援新的查詢方法

whereField(\'表達式\',\'查詢條件\');
whereOrField(\'表達式\',\'查詢條件\');	
           

Field

使用字段的駝峰命名方式。
  • where() 格式
    where( 字段名 , 表達式 , 查詢條件);
               
    表達式包含以下:
    表達式 含義 快捷查詢方法
    = 等于
    <> 不等于
    > 大于
    >= 大于等于
    < 小于
    <= 小于等于
    [NOT] LIKE 模糊查詢

    whereLike/whereNotLike

    [NOT] BETWEEN (不在)區間查詢

    whereBetween/whereNotBetween

    [NOT] IN (不在)IN 查詢

    whereIn/whereNotIn

    [NOT] NULL 查詢字段是否(不)是NULL

    whereNull/whereNotNull

    [NOT] EXISTS EXISTS查詢

    whereExists/whereNotExists

    [NOT] REGEXP 正則(不)比對查詢 (僅支援Mysql)
    [NOT] BETWEEM TIME 時間區間比較 whereBetweenTime
    > TIME 大于某個時間

    whereTime

    < TIME 小于某個時間

    whereTime

    >= TIME 大于等于某個時間

    whereTime

    <= TIME 小于等于某個時間

    whereTime

    EXP 表達式查詢,支援SQL文法

    whereExp

區間查詢(建議使用快捷)

  • link 表達式進行模糊查詢
    $data = Db::table(\'tp_book\')->where(\'title\',\'like\',\'%白%\')->column(\'title\');
    return json($data);
               
    支援使用數組
    // 查詢 title中包含 白和M開頭的書籍
    $data = Db::table(\'tp_book\')
        ->where(\'title\',\'like\',[\'%白%\',\'M%\'],\'OR\')
        ->column(\'title\');
    return json($data);
               
    為了更加友善,應該直接使用

    whereLike

    方法
    Db::name(\'user\')->whereLike(\'name\',\'thinkphp%\')->select();
    Db::name(\'user\')->whereNotLike(\'name\',\'thinkphp%\')->select();
               
  • between 指定區間範圍查找

    查詢條件支援字元串或者數組,例如:

    Db::name(\'user\')->where(\'id\',\'between\',\'1,8\')->select();
               
    和下面的等效:
    Db::name(\'user\')->where(\'id\',\'between\',[1,8])->select();
               
    最快捷的查詢方法是:
    Db::name(\'user\')->whereBetween(\'id\',\'1,8\')->select();
    Db::name(\'user\')->whereNotBetween(\'id\',\'1,8\')->select();
               
  • in 指定索引查找
    // in、not in 指定所有查找
    $data = Db::table(\'tp_book\')->where(\'id\',\'in\',\'1,2,23\')->column(\'title\');
    $data = Db::table(\'tp_book\')->where(\'id\',\'in\',\'[1,2,23]\')->column(\'title\');
    
    $data = Db::table(\'tp_book\')->whereIn(\'id\',\'1,2,34\')->column(\'title\');
    $data = Db::table(\'tp_book\')->whereNotIn(\'id\',\'1,2,3,4,44\')->column(\'title\');
    return json($data);
               
  • Null 查詢字段是否(不)是

    Null

    // null、not null 查詢指定字段是否可以為Null/Not Null
    $data = Db::table(\'tp_access\')->where(\'details\',\'null\')->column(\'user_id\');
    $data = Db::table(\'tp_access\')->where(\'details\',\'notnull\')->column(\'user_id\');
    $data = Db::table(\'tp_access\')->whereNull(\'details\')->column(\'user_id\');
    $data = Db::table(\'tp_access\')->whereNotNull(\'details\')->column(\'user_id\');
    return json($data);
               

EXP:其它查詢

支援更複雜的查詢情況 例如:

Db::name(\'user\')->where(\'id\',\'in\',\'1,3,8\')->select();
           

可以改成:

Db::name(\'user\')->where(\'id\',\'exp\',\' IN (1,3,8) \')->select();
           

exp

查詢的條件不會被當成字元串,是以後面的查詢條件可以使用任何SQL支援的文法,包括使用函數和字段名稱。

$data = Db::table(\'tp_access\')->where(\'id\',\'exp\',\'in (1,2,3,4)\')->column(\'user_id\');// 快捷 ↓
$data = Db::table(\'tp_access\')->whereExp(\'id\',\'in (1,2,3,4)\')->column(\'user_id\');
// 等效于 ==> SELECT `user_id` FROM `tp_access` WHERE ( `id` in (1,2,3,4) )

$data = Db::table(\'tp_book\')->whereExp(\'id\',\'>=20 and user_id =88 \')->column(\'title\');
$data = Db::table(\'tp_book\')->whereExp(\'\',\'id >=20 and user_id =88 \')->column(\'title\');
// 等效于 ==> SELECT `title` FROM `tp_book` WHERE ( `id` >=20 and user_id =88 )
print_r($data);
           

時間查詢

  • 傳統查詢 where()

    where

    方法支援時間比較,例如:
    // 采用比較符号比較時間
    $data = Db::table(\'tp_one\')->where(\'create_time\',\'< time\',\'2016-10-10 00:00:00\')->select();
    // ==> SELECT * FROM `tp_one` WHERE `create_time` < \'2016-10-10 00:00:00\'
    // 在第二參數明确 time 的時候,第三個參數會自動按照完整的time格式填充(年-月-日 時:分:秒)
    
    // 時間區間查詢
    where(\'create_time\', \'between time\', [\'2015-1-1\', \'2016-1-1\']);
               
    第三個參數可以傳入任何有效的時間表達式,會自動識别你的時間字段類型,支援的時間類型包括

    timestamps

    datetime

    date

    int

    區間查詢

    whereTime()

    /

    wherebetween()

    /

    wherebetweenTime()

    :
    // 采用whereTime()區間查詢時間 (whereTime()和between time 結果是一樣的,推薦後者)
    $data = Db::table(\'tp_one\')
        ->where(\'create_time\',\'between time\',[\'2018-01-01\',\'2019-01-01\'])
        ->select();
    $data = Db::table(\'tp_one\')
        ->whereTime(\'create_time\',[\'2018-01-01\',\'2019-01-01\'])
        ->select();
    // ==> SELECT * FROM `tp_one` WHERE `create_time` BETWEEN \'2018-01-01 00:00:00\' AND \'2019-01-01 00:00:00\'
    // wherebetween() 也支援如上的區間Time查詢
    $data = Db::table(\'tp_one\')
        ->whereBetween(\'create_time\',[\'2018-01-01\',\'2019-01-01\'])
        ->select();
    // wherebetweenTime() 也是一個支援時間起始查詢函數
    $data = Db::table(\'tp_one\')
        ->whereBetweenTime(\'create_time\',\'2018-01-01\',\'2019-01-01\')
        ->select();
    // 如果第三個參數為空則代表查詢當天(一天)
               

    whereTime()

    還支援時間便捷固定查詢:
    關鍵字 (whereTime()的第三個參數值) 說明
    today 今天
    yesterday 昨天
    week 本周
    last week 上周
    month 本月
    last month 上月
    year 本年
    last year 去年
    同時還支援指定的時間資料查詢;例如兩小時内就是:

    -2 hour

    whereBetweenTimeField()

    多時間(字)段查詢

    V5.1.17+

    版本開始,可以支援對兩個時間字段的區間比較
    // 查詢有效期内的活動
    Db::name(\'event\')
    	->whereBetweenTimeField(\'start_time\',\'end_time\')
        ->select();	
               
    上面的查詢相當于
    // 查詢有效期内的活動
    Db::name(\'event\')
    	->whereTime(\'start_time\', \'<=\', time())
        ->whereTime(\'end_time\', \'>=\', time())
        ->select();
               
聚合查詢

在應用中我們經常會用到一些統計資料,例如目前所有(或者滿足某些條件)的使用者數、所有使用者的最大積分、使用者的平均成績等等,ThinkPHP為這些統計操作提供了一系列的内置方法,包括:

方法 說明
count 統計數量,參數是要統計的字段名(可選)
max 擷取最大值,參數是要統計的字段名(必須)
min 擷取最小值,參數是要統計的字段名(必須)
avg 擷取平均值,參數是要統計的字段名(必須)
sum 擷取總分,參數是要統計的字段名(必須)
聚合方法如果沒有資料,預設都是0,聚合查詢都可以配合其它查詢條件

V5.1.5+

版本開始,聚合查詢可以支援

JSON

字段類型(MySQL5.7+開始支援JSON)

count()

統計數量: 可以根據表的行數或根據字段的行數

$data = Db::table(\'tp_book\')->count();
// ==> SELECT COUNT(*) AS tp_count FROM `tp_book`
$data = Db::table(\'tp_book\')->count(\'id\');
// ==> SELECT COUNT(`id`) AS tp_count FROM `tp_book`
           

max()/min()

擷取最值:可以根據字段名擷取字段列中最值;如果字段中的不是數值,函數會自動強制轉換,可以通過定義第二參數為“false”來取消強制轉換的行為

// max()/min() 最值函數
$data = Db::table(\'tp_book\')
    ->max(\'user_id\');
// ==> SELECT MAX(`user_id`) AS tp_max FROM `tp_book`
$data = Db::table(\'tp_book\')
    ->max(\'title\');
$data = Db::table(\'tp_book\')
    ->max(\'title\',false); // 和↑條同作用,但是這條将不強制轉換,按照編碼進行
// ==> SELECT MAX(`title`) AS tp_max FROM `tp_book`
           

avg()

平均值計算

$data = Db::table(\'tp_book\')->avg(\'user_id\');
// ==> SELECT AVG(`user_id`) AS tp_avg FROM `tp_book`   
           

sum()

求和計算

$data = Db::table(\'tp_book\')->sum(\'user_id\');
// ==> SELECT SUM(`user_id`) AS tp_sum FROM `tp_book`
           
子查詢
  • 使用

    fetchSql()

    方法,不執行SQL語句而是傳回SQL語句,預設True
    $subQuery = Db::table(\'think_user\')
        ->field(\'id,name\')
        ->where(\'id\', \'>\', 10)
        ->fetchSql(true)
        ->select();
               
    生成的subQuery結果為:
    SELECT `id`,`name` FROM `think_user` WHERE `id` > 10 
               
  • 使用

    buidSql()

    方法,傳回SQL語句且不需要執行select()同時添加兩側括号
    $subQuery = Db::table(\'think_user\')
        ->field(\'id,name\')
        ->where(\'id\', \'>\', 10)
        ->buildSql();
               
    生成的subQuery結果為:
    ( SELECT `id`,`name` FROM `think_user` WHERE `id` > 10 )
               
在SQL語句中我們需要用到子查詢的功能,就是利用SQL1語句的查詢結果給SQL2語句使用

原生SQL語句:(具備子查詢)

SELECT * FROM `tp_one` WHERE id in (SELECT uid FROM tp_two where gender = \'男\');
           

構造ThinkPHP的子查詢代碼:

$sql_1 = Db::table(\'tp_two\')
    ->field(\'uid\')
    // field()方法主要作用是辨別要傳回或者操作的字段,可以用于查詢和寫入操作。
    ->where(\'gender\',\'男\')
    ->buildSql();
$sql = Db::table(\'tp_one\')
    ->whereIn(\'id\',$sql_1)
    ->select();
// ==> SELECT * FROM `tp_one` WHERE `id` = ( SELECT `uid` FROM `tp_two` WHERE `gender` = \'男\' )
// 這裡使用WhereIn出現的問題就是原本應該是 IN 卻變成了 = 符号

$sql_exp =  Db::table(\'tp_one\')
    ->whereExp(\'id\',\'IN\'.$sql_1)
    ->select();
// ==> SELECT * FROM `tp_one` WHERE ( `id` IN( SELECT `uid` FROM `tp_two` WHERE `gender` = \'男\' ) )
// 由于whereIn無法正确的使用,于是采用whereExp()方法構造IN并使用連接配接符連接配接$sql_1
           

使用閉包構造子查詢

IN/NOT IN

EXISTS/NOT EXISTS

之類的查詢可以直接使用閉包作為子查詢,例如:

Db::table(\'think_user\')
    ->where(\'id\', \'IN\', function ($query) {
        $query->table(\'think_profile\')->where(\'status\', 1)->field(\'id\');
    })
    ->select();
           
原生查詢

query()/讀操作

query

方法用于執行

SQL

查詢操作,如果資料非法或者查詢錯誤則傳回false,否則傳回查詢結果資料集(同

select

方法)。

使用示例:

Db::query("select * from think_user where status=1");
           

execute()/寫操作

execute

用于更新和寫入資料的sql操作,如果資料非法或者查詢錯誤則傳回

false

,否則傳回影響的記錄數。

使用示例:

Db::execute("update think_user set name=\'thinkphp\' where status=1");
           
鍊式查詢-建議參考手冊

where

  • 表達式查詢:即之前的那些普通的多個表達式組合的查詢方式

    例如:where比較查詢、whereIn、whereLike……

  • 關聯數組查詢:等值AND和IN函數條件
    // Where數組關聯查詢可以等值AND和IN函數條件
    $data = Db::table(\'tp_one\')->where([
        \'math\'      =>  88,
        \'chinese\'   =>  88,
    ])->select();
    // ==> SELECT * FROM `tp_one` WHERE `math` = 88 AND `chinese` = 88
    $data = Db::table(\'tp_one\')->where([
        \'math\'      =>  88,
        \'chinese\'   =>  [88,99,11],//等效于IN (88,99,11)
    ])->select();
    // ==> SELECT * FROM `tp_one` WHERE `math` = 88 AND `chinese` IN (88,99,11)
               
  • 索引數組查詢:批量設定查詢條件
    // Where索引數組查詢
    $data = Db::table(\'tp_one\')->where([
    		[\'math\',\'<=\',\'88\'],
    		[\'chinese\',\'>\',\'90\'],
    	])->select();
    // ==>  SELECT * FROM `tp_one` WHERE `math` <= 88 AND `chinese` > 90
               
    如果需要事先組裝數組查詢條件,可以使用:
    $map[] = [\'name\',\'like\',\'think\'];
    $map[] = [\'status\',\'=\',1];
               
    數組的各種查詢方式其實可以多樣應用
  • 字元串傳遞

    使用字元串條件直接查詢和操作,例如:

    Db::table(\'think_user\')->where(\'type=1 AND status=1\')->select(); 
               
    最後生成的SQL語句是
    SELECT * FROM think_user WHERE type=1 AND status=1
               
這裡的where多樣運用需要開發者按照自己的喜好和實際的開發需求決定如何使用;如果無法運用就直接使用原生!

table

table

方法主要用于指定操作的資料表。

Db::table(\'think_user\')->where(\'status>1\')->select(); // 指定資料表
Db::table(\'db_name.think_user\')->where(\'status>1\')->select(); //指定資料庫和表
           

如果需要對多表進行操作,可以這樣使用:

Db::field(\'user.name,role.title\')
->table(\'think_user user,think_role role\')
->limit(10)->select();
           

為了盡量避免和mysql的關鍵字沖突,可以建議使用數組方式定義,例如:

Db::field(\'user.name,role.title\')
->table([\'think_user\'=>\'user\',\'think_role\'=>\'role\'])
->limit(10)->select();
           

使用數組方式定義的優勢是可以避免因為表名和關鍵字沖突而出錯的情況。

alias

alias

用于設定目前資料表的别名,便于使用其他的連貫操作;例如join方法等。

示例:

Db::table(\'think_user\')
->alias(\'a\')
->join(\'think_dept b \',\'b.user_id= a.id\')
->select();
           

最終生成的SQL語句類似于:

SELECT * FROM think_user a INNER JOIN think_dept b ON b.user_id= a.id
           

field

field

方法主要作用是辨別要傳回或者操作的字段,可以用于查詢和寫入操作。

  • 指定字段:field()可以在查詢資料、添加資料中都可以運用到,但是在添加中不得違背SQL的規範
    $data = Db::table(\'tp_book\')
        ->where(\'user_id\',\'>\',\'50\')
        ->field(\'title\')
        ->select();
    // ==> SELECT `title` FROM `tp_book` WHERE `user_id` > 50
    
               
  • 使用SQL函數
    $data = Db::table(\'tp_one\')
        ->field(\'SUM(math)\')
        ->select();
    // ==> SELECT SUM(math) FROM `tp_one`
               
  • field方法的參數可以支援數組,例如:
    Db::table(\'think_user\')->field([\'id\',\'title\',\'content\'])->select();
               
  • 字段排除:排除某一個或多個字段,需要在field()的第二參數設定為True預設Falst
    // 排除某一個或多個字段,需要在field()的第二參數設定為True  不支援跨表和join操作。
    $data = Db::table(\'tp_book\')->field(\'user_id\',true)->select();
    // ==> SELECT `id`,`title` FROM `tp_book`
    $data = Db::table(\'tp_book\')->field(\'id,user_id\',true)->select();
    // ==>   SELECT `title` FROM `tp_book`
               

strict

strict

方法用于設定是否嚴格檢查字段名,用法如下:(建議true)

// 關閉字段嚴格檢查
Db::name(\'user\')
    ->strict(false)
    ->insert($data);
           

注意,系統預設值是由資料庫配置參數

fields_strict

決定,是以修改資料庫配置參數可以進行全局的嚴格檢查配置,如下:

// 關閉嚴格檢查字段是否存在
\'fields_strict\'  => false,
           
如果開啟字段嚴格檢查的話,在更新和寫入資料庫的時候,一旦存在非資料表字段的值,則會抛出異常。

limit

limit()

用于限制輸入輸出的資料條數,也可以指定輸出的行數範圍

// limit() 可以指定輸出的條數、行數範圍、輸入的條數限制
$data = Db::table(\'tp_book\')->field(\'title\')->limit(3)->select(); //限制條數
// ==>  SELECT `title` FROM `tp_book` LIMIT 3
$data = Db::table(\'tp_book\')->field(\'title\')->limit(3,3)->select(); // 實作分頁
// ==> SELECT `title` FROM `tp_book` LIMIT 3,3 //limit(起始行,條數)
           

limit

方法也可以用于寫操作,例如更新滿足要求的3條資料:

Db::table(\'think_user\')
->where(\'score\',100)
->limit(3)
->update([\'level\'=>\'A\']);
           

page

page()

方法主要用于分頁查詢。

// page() 分頁查詢
$data = Db::table(\'tp_book\')->field(\'title\')->page(1,3)->select();
// =>  SELECT `title` FROM `tp_book` LIMIT 0,3
$data = Db::table(\'tp_book\')->field(\'title\')->page(2,3)->select();
// =>  SELECT `title` FROM `tp_book` LIMIT 3,3
           

page()直接是規定第一頁第二頁即可,page()方法自動實作LIMIT的分頁補充……而當LIMIT和page同時出現的話,page接受的一個參數代表頁數,而limit的參數代表輸出的每頁條數。(具體見手冊)

order

order()

方法用于對操作的結果排序或者優先級限制。(參考手冊)

Db::table(\'think_user\')
->where(\'status\', 1)
->order(\'id\', \'desc\')
->limit(5)
->select();
 SELECT * FROM `think_user` WHERE `status` = 1 ORDER BY `id` desc LIMIT 5
           
如果沒有指定

desc

或者

asc

排序規則的話,預設為

asc

支援使用數組對多個字段的排序,例如:

Db::table(\'think_user\')
->where(\'status\', 1)
->order([\'order\',\'id\'=>\'desc\'])
->limit(5)
->select(); 
           

最終的查詢SQL可能是

SELECT * FROM `think_user` WHERE `status` = 1 ORDER BY `order`,`id` desc LIMIT 5
           

對于更新資料或者删除資料的時候可以用于優先級限制

Db::table(\'think_user\')
->where(\'status\', 1)
->order(\'id\', \'desc\')
->limit(5)
->delete(); 
           

生成的SQL

DELETE FROM `think_user` WHERE `status` = 1 ORDER BY `id` desc LIMIT 5
           

V5.1.7+

版本開始,如果你需要在

order

方法中使用mysql函數的話,必須使用下面的方式:

Db::table(\'think_user\')
->where(\'status\', 1)
->orderRaw("field(name,\'thinkphp\',\'onethink\',\'kancloud\')")
->limit(5)
->select();
           

group

GROUP

方法通常用于結合合計函數,根據一個或多個列對結果集進行分組 。(參考手冊)

group

方法隻有一個參數,并且隻能使用字元串。

例如,我們都查詢結果按照使用者id進行分組統計:

Db::table(\'think_user\')
    ->field(\'user_id,username,max(score)\')
    ->group(\'user_id\')
    ->select();
           

生成的SQL語句是:

SELECT user_id,username,max(score) FROM think_score GROUP BY user_id
           

也支援對多個字段進行分組,例如:

Db::table(\'think_user\')
    ->field(\'user_id,test_time,username,max(score)\')
    ->group(\'user_id,test_time\')
    ->select();
           

生成的SQL語句是:

SELECT user_id,test_time,username,max(score) FROM think_user GROUP BY user_id,test_time
           

having

HAVING

方法用于配合group方法完成從分組的結果中篩選(通常是聚合條件)資料。

having

方法隻有一個參數,并且隻能使用字元串,例如:

Db::table(\'think_user\')
    ->field(\'username,max(score)\')
    ->group(\'user_id\')
    ->having(\'count(test_time)>3\')
    ->select(); 
           

生成的SQL語句是:

SELECT username,max(score) FROM think_score GROUP BY user_id HAVING count(test_time)>3