推荐优先使用model

查询数据

查询单个数据find

查询单个数据使用find方法,会自带limit 1

  1. // table方法必须指定完整的数据表名
  2. Db::table('think_user')->where('id', 1)->find();

最终生成的SQL语句可能是:

  1. SELECT * FROM `think_user` WHERE `id` = 1 LIMIT 1

find方法查询结果不存在,返回null,否则返回结果数组
如果希望查询数据不存在的时候返回空数组,可以使用

  1. // table方法必须指定完整的数据表名
  2. Db::table('think_user')->where('id', 1)->findOrEmpty();

如果希望在没有找到数据后抛出异常可以使用

  1. Db::table('think_user')->where('id', 1)->findOrFail();

如果没有查找到数据,则会抛出一个think\db\exception\DataNotFoundException异常。
如果没有任何的查询条件 并且也没有调用order方法的话 ,find查询不会返回任何结果。

查询数据集select

查询多个数据(数据集)使用select方法:

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

最终生成的SQL语句可能是:

  1. SELECT * FROM `think_user` WHERE `status` = 1

select方法查询结果是一个数据集对象,如果需要转换为数组可以使用

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

如果希望在没有查找到数据后抛出异常可以使用

  1. Db::table('think_user')->where('status',1)->selectOrFail();

如果没有查找到数据,同样也会抛出一个think\db\exception\DataNotFoundException异常。
如果设置了数据表前缀参数的话,可以使用

  1. Db::name('user')->where('id', 1)->find();
  2. Db::name('user')->where('status', 1)->select();

如果你的数据表没有设置表前缀的话,那么nametable方法效果一致。
findselect方法之前可以使用所有的链式操作(参考链式操作章节)方法。

值和列查询

查询某个字段value

查询某个字段的值可以用

  1. // 返回某个字段的值
  2. Db::table('think_user')->where('id', 1)->value('name');

value方法查询结果不存在,返回null

查询某一列column

查询某一列的值可以用

  1. // 返回数组
  2. Db::table('think_user')->where('status',1)->column('name');
  3. // 指定id字段的值作为索引
  4. Db::table('think_user')->where('status',1)->column('name', 'id');

如果要返回完整数据,并且添加一个索引值的话,可以使用

  1. // 指定id字段的值作为索引 返回所有数据
  2. Db::table('think_user')->where('status',1)->column('*','id');

column方法查询结果不存在,返回空数组

数据分批处理

如果你需要处理成千上百条数据库记录,可以考虑使用chunk方法,该方法一次获取结果集的一小块,然后填充每一小块数据到要处理的闭包,该方法在编写处理大量数据库记录的时候非常有用。
比如,我们可以全部用户表数据进行分批处理,每次处理 100 个用户记录:

  1. Db::table('think_user')->chunk(100, function($users) {
  2. foreach ($users as $user) {
  3. //
  4. }
  5. });

你可以通过从闭包函数中返回false来中止对后续数据集的处理:

  1. Db::table('think_user')->chunk(100, function($users) {
  2. foreach ($users as $user) {
  3. // 处理结果集...
  4. if($user->status==0){
  5. return false;
  6. }
  7. }
  8. });

也支持在chunk方法之前调用其它的查询方法,例如:

  1. Db::table('think_user')
  2. ->where('score','>',80)
  3. ->chunk(100, function($users) {
  4. foreach ($users as $user) {
  5. //
  6. }
  7. });

chunk方法的处理默认是根据主键查询,支持指定字段,例如:

  1. Db::table('think_user')->chunk(100, function($users) {
  2. // 处理结果集...
  3. return false;
  4. },'create_time');

并且支持指定处理数据的顺序。

  1. Db::table('think_user')->chunk(100, function($users) {
  2. // 处理结果集...
  3. return false;
  4. },'create_time', 'desc');

chunk方法一般用于命令行操作批处理数据库的数据,不适合WEB访问处理大量数据,很容易导致超时。
游标查询
如果你需要处理大量的数据,可以使用新版提供的游标查询功能,该查询方式利用了PHP的生成器特性,可以大幅减少大量数据查询的内存开销问题。

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

cursor方法返回的是一个生成器对象,user变量是数据表的一条数据(数组)。

添加数据

更新数据

删除数据

查询表达式

链式操作

where(查询条件)

详见where详解

table(实际表名)

table方法主要用于指定操作的数据表。
用法
一般情况下,操作模型的时候系统能够自动识别当前对应的数据表,所以,使用table方法的情况通常是为了:

  • 切换操作的数据表;
  • 对多表进行操作;
    例如: ``` Db::table(‘think_user’)->where(‘status>1’)->select();
  1. 也可以在`table`方法中指定数据库,例如:

Db::table(‘db_name.think_user’)->where(‘status>1’)->select();

  1. `table`方法指定的数据表需要完整的表名,但可以采用`name`方式简化数据表前缀的传入,例如:

Db::name(‘user’)->where(‘status>1’)->select();

  1. 会自动获取当前模型对应的数据表前缀来生成`think_user`数据表名称。<br />需要注意的是`table`方法不会改变数据库的连接,所以你要确保当前连接的用户有权限操作相应的数据库和数据表。<br />如果需要对多表进行操作,可以这样使用:

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

  1. 为了尽量避免和`mysql`的关键字冲突,可以建议使用数组方式定义,例如:

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

  1. 使用数组方式定义的优势是可以避免因为表名和关键字冲突而出错的情况。
  2. ## alias(表别名)
  3. `alias`用于设置当前数据表的别名,便于使用其他的连贯操作例如`join`方法等。<br />
  4. 示例:

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

  1. 最终生成的SQL语句类似于:

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

  1. 可以传入数组批量设置数据表以及别名,例如:

Db::table(‘think_user’) ->alias([‘think_user’=>’user’,’think_dept’=>’dept’]) ->join(‘think_dept’,’dept.user_id= user.id’) ->select();

  1. 最终生成的SQL语句类似于:

SELECT * FROM think_user user INNER JOIN think_dept dept ON dept.user_id= user.id

  1. ## field(字段)
  2. `field`方法主要作用是标识要返回或者操作的字段,可以用于查询和写入操作。
  3. ### 用于查询
  4. #### 指定字段
  5. 在查询操作中field方法是使用最频繁的。

Db::table(‘user’)->field(‘id,title,content’)->select();

  1. 这里使用`field`方法指定了查询的结果集中包含`id,title,content`三个字段的值。执行的SQL相当于:

SELECT id,title,content FROM user

  1. 可以给某个字段设置别名,例如:

Db::table(‘user’)->field(‘id,nickname as name’)->select();

  1. 执行的SQL语句相当于:

SELECT id,nickname as name FROM user

  1. #### 使用SQL函数
  2. 可以在`fieldRaw`方法中直接使用函数,例如:

Db::table(‘user’)->fieldRaw(‘id,SUM(score)’)->select();

  1. 执行的SQL相当于:

SELECT id,SUM(score) FROM user

  1. 除了`select`方法之外,所有的查询方法,包括`find`等都可以使用`field`方法。
  2. #### 使用数组参数
  3. `field`方法的参数可以支持数组,例如:

Db::table(‘user’)->field([‘id’,’title’,’content’])->select();

  1. 最终执行的SQL和前面用字符串方式是等效的。<br />数组方式的定义可以为某些字段定义别名,例如:

Db::table(‘user’)->field([‘id’,’nickname’=>’name’])->select();

  1. 执行的SQL相当于:

SELECT id,nickname as name FROM user

  1. #### 获取所有字段
  2. 如果有一个表有非常多的字段,需要获取所有的字段(这个也许很简单,因为不调用field方法或者直接使用空的field方法都能做到):

Db::table(‘user’)->select(); Db::table(‘user’)->field(‘*’)->select();

  1. 上面的用法是等效的,都相当于执行SQL

SELECT * FROM user

  1. 但是这并不是我说的获取所有字段,而是显式的调用所有字段(对于对性能要求比较高的系统,这个要求并不过分,起码是一个比较好的习惯),下面的用法可以完成预期的作用:

Db::table(‘user’)->field(true)->select();

  1. `field(true)`的用法会显式的获取数据表的所有字段列表,哪怕你的数据表有100个字段。
  2. #### 字段排除
  3. 如果我希望获取排除数据表中的`content`字段(文本字段的值非常耗内存)之外的所有字段值,我们就可以使用`field`方法的排除功能,例如下面的方式就可以实现所说的功能:

Db::table(‘user’)->withoutField(‘content’)->select();

  1. 则表示获取除了`content`之外的所有字段,要排除更多的字段也可以:

Db::table(‘user’)->withoutField(‘user_id,content’)->select(); //或者用 Db::table(‘user’)->withoutField([‘user_id’,’content’])->select();

  1. 注意的是 字段排除功能不支持跨表和`join`操作。
  2. ### 用于写入
  3. 除了查询操作之外,`field`方法还有一个非常重要的安全功能--`字段合法性检测``field`方法结合数据库的写入方法使用就可以完成表单提交的字段合法性检测,如果我们在表单提交的处理方法中使用了:

Db::table(‘user’)->field(‘title,email,content’)->insert($data);

  1. 即表示表单中的合法字段只有`title`,`email``content`字段,无论用户通过什么手段更改或者添加了浏览器的提交字段,都会直接屏蔽。因为,其他所有字段我们都不希望由用户提交来决定,你可以通过自动完成功能定义额外需要自动写入的字段。
  2. > 在开启数据表字段严格检查的情况下,提交了非法字段会抛出异常,可以在数据库设置文件中设置:

// 关闭严格字段检查 ‘fields_strict’ => false,

  1. ## strict(字段严格检查)
  2. `strict`方法用于设置是否严格检查字段名,用法如下:

// 关闭字段严格检查 Db::name(‘user’) ->strict(false) ->insert($data);

  1. 注意,系统默认值是由数据库配置参数`fields_strict`决定,因此修改数据库配置参数可以进行全局的严格检查配置,如下:

// 关闭严格检查字段是否存在 ‘fields_strict’ => false,

  1. > 如果开启字段严格检查的话,在更新和写入数据库的时候,一旦存在非数据表字段的值,则会抛出异常。
  2. ## limit(`LIMIT`)
  3. `limit`方法主要用于指定查询和操作的数量。
  4. - `limit`方法可以兼容所有的数据库驱动类的
  5. ### 限制结果数量
  6. 例如获取满足要求的10个用户,如下调用即可:

Db::table(‘user’) ->where(‘status’,1) ->field(‘id,name’) ->limit(10) ->select();

  1. `limit`方法也可以用于写操作,例如更新满足要求的3条数据:

Db::table(‘user’) ->where(‘score’,100) ->limit(3) ->update([‘level’=>’A’]);

  1. 如果用于`insertAll`方法的话,则可以分批多次写入,每次最多写入`limit`方法指定的数量。

Db::table(‘user’) ->limit(100) ->insertAll($userList);

  1. ### 分页查询
  2. 用于文章分页查询是`limit`方法比较常用的场合,例如:

Db::table(‘article’)->limit(10,25)->select();

  1. 表示查询文章数据,从第10行开始的25条数据(可能还取决于`where`条件和`order`排序的影响 这个暂且不提)。<br />对于大数据表,尽量使用`limit`限制查询结果,否则会导致很大的内存开销和性能问题。
  2. ## page(分页页码)
  3. `page`方法主要用于分页查询。<br />我们在前面已经了解了关于`limit`方法用于分页查询的情况,而`page`方法则是更人性化的进行分页查询的方法,例如还是以文章列表分页为例来说,如果使用`limit`方法,我们要查询第一页和第二页(假设我们每页输出10条数据)写法如下:

// 查询第一页数据 Db::table(‘article’)->limit(0,10)->select(); // 查询第二页数据 Db::table(‘article’)->limit(10,10)->select();

  1. 虽然利用扩展类库中的分页类`Page`可以自动计算出每个分页的`limit`参数,但是如果要自己写就比较费力了,如果用`page`方法来写则简单多了,例如:

// 查询第一页数据 Db::table(‘article’)->page(1,10)->select(); // 查询第二页数据 Db::table(‘article’)->page(2,10)->select();

  1. 显而易见的是,使用`page`方法你不需要计算每个分页数据的起始位置,`page`方法内部会自动计算。<br />`page`方法还可以和`limit`方法配合使用,例如:

Db::table(‘article’)->limit(25)->page(3)->select();

  1. `page`方法只有一个值传入的时候,表示第几页,而`limit`方法则用于设置每页显示的数量,也就是说上面的写法等同于:

Db::table(‘article’)->page(3,25)->select();

  1. ## paginate(分页实现)
  2. ThinkPHP内置了分页实现,要给数据添加分页输出功能变得非常简单,可以直接在`Db`类查询的时候调用`paginate`方法:

// 查询状态为1的用户数据 并且每页显示10条数据 $list = Db::name(‘user’)->where(‘status’,1)->order(‘id’, ‘desc’)->paginate(10);

// 渲染模板输出 return view(‘index’, [‘list’ => $list]);

  1. 模板文件中分页输出代码如下:

    {volist name=’list’ id=’user’}
  • {$user.nickname}
  • {/volist}
{$list|raw} 也可以单独赋值分页输出的模板变量 // 查询状态为1的用户数据 并且每页显示10条数据 $list = Db::name(‘user’)->where(‘status’,1)->order(‘id’, ‘desc’)->paginate(10); // 获取分页显示 $page = $list->render(); return view(‘index’, [‘list’ => $list, ‘page’ => $page]); 模板文件中分页输出代码如下:
    {volist name=’list’ id=’user’}
  • {$user.nickname}
  • {/volist}
{$page|raw} 默认情况下,生成的分页输出是完整分页功能,带总分页数据和上下页码,分页样式只需要通过样式修改即可,完整分页默认生成的分页输出代码为:
  1. 如果你需要单独获取总的数据,可以使用

// 查询状态为1的用户数据 并且每页显示10条数据 $list = Db::name(‘user’)->where(‘status’,1)->order(‘id’ ,’desc’)->paginate(10); // 获取总记录数 $count = $list->total(); return view(‘index’, [‘list’ => $list, ‘count’ => $count]);

  1. ### 传入总记录数
  2. 支持传入总记录数而不会自动进行总数计算,例如:

// 查询状态为1的用户数据 并且每页显示10条数据 总记录数为1000 $list = Db::name(‘user’)->where(‘status’,1)->paginate(10,1000); // 获取分页显示 $page = $list->render();

return view(‘index’, [‘list’ => $list, ‘page’ => $page]);

  1. > 对于`UNION`查询以及一些特殊的复杂查询,推荐使用这种方式首先单独查询总记录数,然后再传入分页方法
  2. ### 分页后数据处理
  3. 支持分页类后数据直接`each`遍历处理,方便修改分页后的数据,而不是只能通过模型的获取器来补充字段。

$list = Db::name(‘user’)->where(‘status’,1)->order(‘id’, ‘desc’)->paginate()->each(function($item, $key){ $item[‘nickname’] = ‘think’; return $item; });

  1. 如果是模型类操作分页数据的话,`each`方法的闭包函数中不需要使用返回值,例如:

$list = User::where(‘status’,1)->order(‘id’, ‘desc’)->paginate()->each(function($item, $key){ $item->nickname = ‘think’; });

  1. ### 简洁分页
  2. 如果你仅仅需要输出一个 仅仅只有上下页的分页输出,可以使用下面的简洁分页代码:

// 查询状态为1的用户数据 并且每页显示10条数据 $list = Db::name(‘user’)->where(‘status’,1)->order(‘id’, ‘desc’)->paginate(10, true);

// 渲染模板输出 return view(‘index’, [‘list’ => $list]);

  1. 简洁分页模式的输出代码为:
  1. 由于简洁分页模式不需要查询总数据数,因此可以提高查询性能。
  2. ### 分页参数
  3. 主要的分页参数如下:
  4. |
  5. 参数
  6. | 描述
  7. |
  8. | --- | --- |
  9. |
  10. list_rows
  11. | 每页数量
  12. |
  13. |
  14. page
  15. | 当前页
  16. |
  17. |
  18. path
  19. | url路径
  20. |
  21. |
  22. query
  23. | url额外参数
  24. |
  25. |
  26. fragment
  27. | url锚点
  28. |
  29. |
  30. var_page
  31. | 分页变量
  32. |
  33. 分页参数的设置可以在调用分页方法的时候传入,例如:

$list = Db::name(‘user’)->where(‘status’,1)->paginate([ ‘list_rows’=> 20, ‘var_page’ => ‘page’, ]);

  1. > 如果需要在分页的时候传入查询条件,可以使用`query`参数拼接额外的查询参数
  2. ### 自定义分页类
  3. 如果你需要自定义分页,可以扩展一个分页驱动。<br />然后在`provider.php`定义文件中重新绑定

return [ ‘think\Paginator’ => ‘app\common\Bootstrap’ ];

  1. ## paginateX(大数据分页)
  2. 对于大量数据的分页查询,系统提供了一个高性能的`paginateX`分页查询方法,用法和`paginate`分页查询存在一定区别。如果你要分页查询的数据量在百万级以上,使用`paginateX`方法会有明显的提升,尤其是在分页数较大的情况下。并且由于针对大数据量而设计,该分页查询只能采用简洁分页模式,所以没有总数。<br />分页查询的排序字段一定要使用索引字段,并且是连续的整型,否则会有数据遗漏。<br />主要场景是针对主键进行分页查询,默认使用主键倒序查询分页数据。

$list = Db::name(‘user’)->where(‘status’,1)->paginateX(20);

  1. 也可以在查询的时候可以指定主键和排序

$list = Db::name(‘user’)->where(‘status’,1)->paginateX(20, ‘id’, ‘desc’);

  1. 查询方法会执行两次查询,第一次查询用于查找满足当前查询条件的最大或者最小值,然后配合主键查询条件来进行分页数据查询。
  2. ## order(排序)
  3. `order`方法用于对操作的结果排序或者优先级限制。<br />用法如下:

Db::table(‘user’) ->where(‘status’, 1) ->order(‘id’, ‘desc’) ->limit(5) ->select();

  1. ```
  2. SELECT * FROM `user` WHERE `status` = 1 ORDER BY `id` desc LIMIT 5

如果没有指定desc或者asc排序规则的话,默认为asc
支持使用数组对多个字段的排序,例如:

  1. Db::table('user')
  2. ->where('status', 1)
  3. ->order(['order','id'=>'desc'])
  4. ->limit(5)
  5. ->select();

最终的查询SQL可能是

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

对于更新数据或者删除数据的时候可以用于优先级限制

  1. Db::table('user')
  2. ->where('status', 1)
  3. ->order('id', 'desc')
  4. ->limit(5)
  5. ->delete();

生成的SQL

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

如果你需要在order方法中使用mysql函数的话,必须使用下面的方式:

  1. Db::table('user')
  2. ->where('status', 1)
  3. ->orderRaw("field(name,'thinkphp','onethink','kancloud')")
  4. ->limit(5)
  5. ->select();

group(聚合查询GROUP

GROUP方法通常用于结合合计函数,根据一个或多个列对结果集进行分组 。
group方法只有一个参数,并且只能使用字符串。
例如,我们都查询结果按照用户id进行分组统计:

  1. Db::table('user')
  2. ->field('user_id,username,max(score)')
  3. ->group('user_id')
  4. ->select();

生成的SQL语句是:

  1. SELECT user_id,username,max(score) FROM score GROUP BY user_id

也支持对多个字段进行分组,例如:

  1. Db::table('user')
  2. ->field('user_id,test_time,username,max(score)')
  3. ->group('user_id,test_time')
  4. ->select();

生成的SQL语句是:

  1. SELECT user_id,test_time,username,max(score) FROM user GROUP BY user_id,test_time

having(聚合条件)

HAVING方法用于配合group方法完成从分组的结果中筛选(通常是聚合条件)数据。
having方法只有一个参数,并且只能使用字符串,例如:

  1. Db::table('score')
  2. ->field('username,max(score)')
  3. ->group('user_id')
  4. ->having('count(test_time)>3')
  5. ->select();

生成的SQL语句是:

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

join(连表)

JOIN方法用于根据两个或多个表中的列之间的关系,从这些表中查询数据。join通常有下面几种类型,不同类型的join操作会影响返回的数据结果。

  • INNER JOIN: 等同于JOIN(默认的JOIN类型),如果表中有至少一个匹配,则返回行
  • LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行
  • RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
  • FULL JOIN: 只要其中一个表中存在匹配,就返回行

    说明

    ``` join ( mixed join [, mixed $condition = null [, string $type = ‘INNER’]] ) leftJoin ( mixed join [, mixed $condition = null ] ) rightJoin ( mixed join [, mixed $condition = null ] ) fullJoin ( mixed join [, mixed $condition = null ] )
  1. ### 参数
  2. #### join

要关联的(完整)表名以及别名

  1. 支持的写法:
  2. - 写法1:[ '完整表名或者子查询'=>'别名' ]
  3. - 写法2'不带数据表前缀的表名'(自动作为别名)
  4. - 写法2'不带数据表前缀的表名 别名'
  5. #### condition

关联条件,只能是字符串。

  1. #### type

关联类型。可以为:INNERLEFTRIGHTFULL,不区分大小写,默认为INNER

  1. #### 返回值
  2. 模型对象
  3. ### 举例

Db::table(‘think_artist’) ->alias(‘a’) ->join(‘work w’,’a.id = w.artist_id’) ->join(‘card c’,’a.card_id = c.id’) ->select();

  1. ```
  2. Db::table('think_user')
  3. ->alias('a')
  4. ->join(['think_work'=>'w'],'a.id=w.artist_id')
  5. ->join(['think_card'=>'c'],'a.card_id=c.id')
  6. ->select();

默认采用INNER JOIN方式,如果需要用其他的JOIN方式,可以改成

  1. Db::table('think_user')
  2. ->alias('a')
  3. ->leftJoin('word w','a.id = w.artist_id')
  4. ->select();

表名也可以是一个子查询

  1. $subsql = Db::table('think_work')
  2. ->where('status',1)
  3. ->field('artist_id,count(id) count')
  4. ->group('artist_id')
  5. ->buildSql();
  6. Db::table('think_user')
  7. ->alias('a')
  8. ->join([$subsql=> 'w'], 'a.artist_id = w.artist_id')
  9. ->select();

union(合并查询)

UNION操作用于合并两个或多个SELECT语句的结果集。
使用示例:

  1. Db::field('name')
  2. ->table('think_user_0')
  3. ->union('SELECT name FROM think_user_1')
  4. ->union('SELECT name FROM think_user_2')
  5. ->select();

闭包用法:

  1. Db::field('name')
  2. ->table('think_user_0')
  3. ->union(function ($query) {
  4. $query->field('name')->table('think_user_1');
  5. })
  6. ->union(function ($query) {
  7. $query->field('name')->table('think_user_2');
  8. })
  9. ->select();

或者

  1. Db::field('name')
  2. ->table('think_user_0')
  3. ->union([
  4. 'SELECT name FROM think_user_1',
  5. 'SELECT name FROM think_user_2',
  6. ])
  7. ->select();

支持UNION ALL 操作,例如:

  1. Db::field('name')
  2. ->table('think_user_0')
  3. ->unionAll('SELECT name FROM think_user_1')
  4. ->unionAll('SELECT name FROM think_user_2')
  5. ->select();

或者

  1. Db::field('name')
  2. ->table('think_user_0')
  3. ->union(['SELECT name FROM think_user_1', 'SELECT name FROM think_user_2'], true)
  4. ->select();

每个union方法相当于一个独立的SELECT语句。
UNION内部的SELECT语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条SELECT语句中的列的顺序必须相同。`

distinct(去重)

DISTINCT方法用于返回唯一不同的值 。
例如数据库表中有以下数据
图片
以下代码会返回user_login字段不同的数据

  1. Db::table('think_user')->distinct(true)->field('user_login')->select();

生成的SQL语句是:

  1. SELECT DISTINCT user_login FROM think_user

返回以下数组

  1. array(2) {
  2. [0] => array(1) {
  3. ["user_login"] => string(7) "chunice"
  4. }
  5. [1] => array(1) {
  6. ["user_login"] => string(5) "admin"
  7. }
  8. }

distinct方法的参数是一个布尔值。

lock(锁定查询)

Lock方法是用于数据库的锁机制,如果在查询或者执行操作的时候使用:

  1. Db::name('user')->where('id',1)->lock(true)->find();

就会自动在生成的SQL语句最后加上FOR UPDATE或者FOR UPDATE NOWAIT(Oracle数据库)。
lock方法支持传入字符串用于一些特殊的锁定要求,例如:

  1. Db::name('user')->where('id',1)->lock('lock in share mode')->find();

cache(查询缓存)

cache方法用于查询缓存操作,也是连贯操作方法之一。
cache可以用于selectfindvaluecolumn方法,以及其衍生方法,使用cache方法后,在缓存有效期之内不会再次进行数据库查询操作,而是直接获取缓存中的数据,关于数据缓存的类型和设置可以参考缓存部分。
下面举例说明,例如,我们对find方法使用cache方法如下:

  1. Db::table('user')->where('id',5)->cache(true)->find();

第一次查询结果会被缓存,第二次查询相同的数据的时候就会直接返回缓存中的内容,而不需要再次进行数据库查询操作。
默认情况下, 缓存有效期是由默认的缓存配置参数决定的,但cache方法可以单独指定,例如:

  1. Db::table('user')->cache(true,60)->find();
  2. // 或者使用下面的方式 是等效的
  3. Db::table('user')->cache(60)->find();

表示对查询结果的缓存有效期60秒。
cache方法可以指定缓存标识:

  1. Db::table('user')->cache('key',60)->find();

指定查询缓存的标识可以使得查询缓存更有效率。
这样,在外部就可以通过\think\Cache类直接获取查询缓存的数据,例如:

  1. $result = Db::table('user')->cache('key',60)->find();
  2. $data = \think\facade\Cache::get('key');

cache方法支持设置缓存标签,例如:

  1. Db::table('user')->cache('key',60,'tagName')->find();

缓存自动更新

这里的缓存自动更新是指一旦数据更新或者删除后会自动清理缓存(下次获取的时候会自动重新缓存)。
当你删除或者更新数据的时候,可以调用相同keycache方法,会自动更新(清除)缓存,例如:

  1. Db::table('user')->cache('user_data')->select([1,3,5]);
  2. Db::table('user')->cache('user_data')->update(['id'=>1,'name'=>'thinkphp']);
  3. Db::table('user')->cache('user_data')->select([1,3,5]);

最后查询的数据不会受第一条查询缓存的影响,确保查询和更新或者删除使用相同的缓存标识才能自动清除缓存。
如果使用主键进行查询和更新(或者删除)的话,无需指定缓存标识会自动更新缓存

  1. Db::table('user')->cache(true)->find(1);
  2. Db::table('user')->cache(true)->where('id', 1)->update(['name'=>'thinkphp']);
  3. Db::table('user')->cache(true)->find(1);

comment(生成SQL注释)

COMMENT方法 用于在生成的SQL语句中添加注释内容,例如:

  1. Db::table('think_score')->comment('查询考试前十名分数')
  2. ->field('username,score')
  3. ->limit(10)
  4. ->order('score desc')
  5. ->select();

最终生成的SQL语句是:

  1. SELECT username,score FROM think_score ORDER BY score desc LIMIT 10 /* 查询考试前十名分数 */

fetchSql(不执行返回SQL)

fetchSql用于直接返回SQL而不是执行查询,适用于任何的CURD操作方法。 例如:

  1. echo Db::table('user')->fetchSql(true)->find(1);

输出结果为:

  1. SELECT * FROM user where `id` = 1

对于某些NoSQL数据库可能不支持fetchSql方法

force(强制索引操作)

force方法用于数据集的强制索引操作,例如:

  1. Db::table('user')->force('user')->select();

对查询强制使用user索引,user必须是数据表实际创建的索引名称。

partition(分表)

partition方法用于MySQL数据库的分区查询,用法如下:

  1. // 用于查询
  2. Db::name('log')
  3. ->partition(['p1','p2'])
  4. ->select();
  5. // 用于写入
  6. Db::name('user')
  7. ->partition('p1')
  8. ->insert(['name' => 'think', 'score' => 100']);

failException(查询数据抛出异常)

failException设置查询数据为空时是否需要抛出异常,用于selectfind方法,例如:

  1. // 数据不存在的话直接抛出异常
  2. Db::name('blog')
  3. ->where('status',1)
  4. ->failException()
  5. ->select();
  6. // 数据不存在返回空数组 不抛异常
  7. Db::name('blog')
  8. ->where('status',1)
  9. ->failException(false)
  10. ->select();

或者可以使用更方便的查空报错

  1. // 查询多条
  2. Db::name('blog')
  3. ->where('status', 1)
  4. ->selectOrFail();
  5. // 查询单条
  6. Db::name('blog')
  7. ->where('status', 1)
  8. ->findOrFail();

sequence(pgsql数据库指定自增序列名)

sequence方法用于pgsql数据库指定自增序列名,其它数据库不必使用,用法为:

  1. Db::name('user')
  2. ->sequence('user_id_seq')
  3. ->insert(['name'=>'thinkphp']);

replace(insertinsertAll时适用)

replace方法用于设置MySQL数据库insert方法或者insertAll方法写入数据的时候是否适用REPLACE方式。

  1. Db::name('user')
  2. ->replace()
  3. ->insert($data);

extra(CRUD额外)

extra方法可以用于CURD查询,例如:

  1. Db::name('user')
  2. ->extra('IGNORE')
  3. ->insert(['name' => 'think']);
  4. Db::name('user')
  5. ->extra('DELAYED')
  6. ->insert(['name' => 'think']);
  7. Db::name('user')
  8. ->extra('SQL_BUFFER_RESULT')
  9. ->select();

duplicate(DUPLICATE查询)

用于设置DUPLICATE查询,用法示例:

  1. Db::name('user')
  2. ->duplicate(['score' => 10])
  3. ->insert(['name' => 'think']);

procedure(存储过程调用)

procedure方法用于设置当前查询是否为存储过程查询,用法如下:

  1. $resultSet = Db::procedure(true)
  2. ->query('call procedure_name');

聚合查询

在应用中我们经常会用到一些统计数据,例如当前所有(或者满足某些条件)的用户数、所有用户的最大积分、用户的平均成绩等等,ThinkPHP为这些统计操作提供了一系列的内置方法,包括:

| 方法 | 说明 | | —- | —- |

| count | 统计数量,参数是要统计的字段名(可选) |

| max | 获取最大值,参数是要统计的字段名(必须) |

| min | 获取最小值,参数是要统计的字段名(必须) |

| avg | 获取平均值,参数是要统计的字段名(必须) |

| sum | 获取总分,参数是要统计的字段名(必须) |

聚合方法如果没有数据,默认都是0,聚合查询都可以配合其它查询条件

用法示例

获取用户数:

  1. Db::table('think_user')->count();

实际生成的SQL语句是:

  1. SELECT COUNT(*) AS tp_count FROM `think_user` LIMIT 1

或者根据字段统计:

  1. Db::table('think_user')->count('id');

生成的SQL语句是:

  1. SELECT COUNT(id) AS tp_count FROM `think_user` LIMIT 1

获取用户的最大积分:

  1. Db::table('think_user')->max('score');

生成的SQL语句是:

  1. SELECT MAX(score) AS tp_max FROM `think_user` LIMIT 1

如果你要获取的最大值不是一个数值,可以使用第二个参数关闭强制转换

  1. Db::table('think_user')->max('name',false);

获取积分大于0的用户的最小积分:

  1. Db::table('think_user')->where('score', '>', 0)->min('score');

max方法一样,min也支持第二个参数用法

  1. Db::table('think_user')->where('score', '>', 0)->min('name',false);

获取用户的平均积分:

  1. Db::table('think_user')->avg('score');

生成的SQL语句是:

  1. SELECT AVG(score) AS tp_avg FROM `think_user` LIMIT 1

统计用户的总成绩:

  1. Db::table('think_user')->where('id',10)->sum('score');

生成的SQL语句是:

  1. SELECT SUM(score) AS tp_sum FROM `think_user` LIMIT 1

如果你要使用group进行聚合查询,需要自己实现查询,例如:

  1. Db::table('score')->field('user_id,SUM(score) AS sum_score')->group('user_id')->select();