如果想了解更多相关知识,可以前往我的个人博客看看:eyes++的个人空间
一:连接数据库与模型初探
ThinkPHP 采用内置抽象层将不同的数据库操作进行封装处理,数据抽象层基于 PDO 模式,无须针对不同的数据库编写相应的代码。使用数据库的第一步,就是连接数据库,在根目录的 config 下的 database.php 可以设置数据库连接信息,大部分系统已经给了默认值,你只需要修改和填写需要的值即可。
其中default配置用于设置默认使用的数据库连接配置。connections配置具体的数据库连接信息,default配置参数定义的连接配置必须要存在。
type | 数据库 |
---|---|
mysql | MySQL |
sqlite | SqLite |
pgsql | PostgreSQL |
sqlsrv | SqlServer |
mongo | MongoDb |
oracle | Oracle |
下面是默认支持的数据库连接信息:
参数名 | 描述 | 默认值 |
---|---|---|
type | 数据库类型 | 无 |
hostname | 数据库地址 | 127.0.0.1 |
database | 数据库名称 | 无 |
username | 数据库用户名 | 无 |
password | 数据库密码 | 无 |
hostport | 数据库端口号 | 无 |
dsn | 数据库连接dsn信息 | 无 |
params | 数据库连接参数 | 空 |
charset | 数据库编码 | utf8 |
prefix | 数据库的表前缀 | 无 |
deploy | 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) | 0 |
rw_separate | 数据库读写是否分离 主从式有效 | false |
master_num | 读写分离后 主服务器数量 | 1 |
slave_no | 指定从服务器序号 | 无 |
fields_strict | 是否严格检查字段是否存在 | true |
fields_cache | 是否开启字段缓存 | false |
schema_cache_path | 字段缓存目录 | 无 |
trigger_sql | 是否开启SQL监听 | true |
auto_timestamp | 自动写入时间戳字段 | false |
query | 指定查询对象 | think\db\Query |
\think\facade\Db::connect('demo')
->table('user')
->find();
connect方法必须在查询的最开始调用,而且必须紧跟着调用查询方法,否则可能会导致部分查询失效或者依然使用默认的数据库连接。且动态连接数据库的connect方法仅对当次查询有效。这种方式的动态连接和切换数据库比较方便,经常用于多数据库连接的应用需求。
对于本地测试,会优先采用.env 的配置信息,可以通过删除改变.env 的配置,或删除.env 来验证 database 的执行优先级,操作中我们和 database 配置对应上即可:
现在来测试有没有成功连接:
二:查询构造器(基础)
在学习查询之前可以先了解一下一个新方法:Db::getLastSql()
,该方法可以返回最近一条SQL查询的原生语句。我在这里的演示是使用了我的myemployees库内容如下:
1) 查询数据
查询单个数据
查询单个数据一般使用find方法。如果没有任何的查询条件,并且也没有调用order方法的话 ,find查询不会返回任何结果。
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result = json(Db::table('employees')->where('employee_id', 100)->find());
return Db::getLastSql() . '<br>' . $result;
}
}
find方法查询结果不存在,返回 null,否则返回结果数组,如果希望查询数据不存在的时候返回空数组,可以如下修改:
$result = Db::table('employees')->where('employee_id', 99)->findOrEmpty();
如果希望在没有找到数据后抛出异常可以如下使用,如果没有查找到数据,则会抛出一个think\db\exception\DataNotFoundException
异常。
$result = Db::table('employees')->where('employee_id', 99)->findOrFail();
查询数据集
查询多个数据(数据集)使用select方法:
select 方法查询结果是一个数据集对象,如果需要转换为数组可以如下使用,但一般DB操作返回是默认是数组,这种情况下调用toArray()会报错,别问我是怎么知道的。。。。
$result = Db::table('employees')->where('employee_id', 102)->select()->toArray();
如果希望在没有查找到数据后抛出异常可以如下使用,如果没有查找到数据,同样也会抛出一个think\db\exception\DataNotFoundException
异常
$result = Db::table('employees')->where('employee_id', 102)->select()->selectOrFail();
如果设置了数据表前缀参数的话,可以使用name替代table,如果表名为"tp_user",然后在数据库设置那里添加了表前缀"tp_",那么查询时可以用name('user')
替代table('tp_user')
。如果你的数据表没有设置表前缀的话,那么name和table方法效果一致。
值和列查询
查询某个字段的值可以用value(),如果不存在则返回null,如果有多个结果则只返回第一个。
查询某一列的值可以用column(),第一个参数是返回的值,第二个参数的值作为索引。
数据分批处理
如果处理的数据量巨大,成百上千那种,一次性读取有可能会导致内存开销过大,为了避免内存处理太多数据出错,可以使用 chunk()方法分批处理数据,该方法一次获取结果集的一小块,然后填充每一小块数据到要处理的闭包,该方法在编写处理大量数据库记录的时候非常有用。比如,我们可以全部员工表数据进行分批处理,每次处理 3 个员工记录,先展示chunk分批次处理的特性。
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
// function传入的$data代表所有数据
$result = Db::table('employees')->chunk(3, function ($data){
foreach ($data as $data) {
dump($data);
}
echo 1;
});
}
}
如果要给员工计算年薪,那就是 月薪*12*(1+奖金率),那样就可以通过如下方法计算了:
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
// function传入的$data代表所有数据
$result = Db::table('employees')->chunk(3, function ($data){
foreach ($data as $data) {
if (isset($data['commission_pct'])) {
echo $data['employee_id'] . ' ' . (12*$data['salary']*(1+$data['commission_pct'])) . "<br>";
} else {
echo $data['employee_id'] . ' ' . (12*$data['salary']) . "<br>";
}
}
echo 1 . "<br>";
});
}
}
chunk方法的处理默认是根据主键查询,支持指定字段,并且支持指定处理数据的顺序。
Db::table('think_user')->chunk(100, function($users) {
// 处理结果集...
return false;
},'create_time', 'desc');
游标查询
可以利用游标查询功能,可以大幅度减少海量数据的内存开销,它利用了 PHP 生 成器特性。每次查询只读一行,然后再读取时,自动定位到下一行继续读取,cursor方法返回的是一个生成器对象。
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result = Db::table('employees')->cursor();
foreach ($result as $e){
echo $e['last_name'] . "<br>";
};
}
}
2) 添加数据
单数据新增
单数据新增一般使用insert()方法插入,如果新增成功会返回一个1,没有指定的列的值默认为null。
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$data = [
'employee_id' => '99',
'first_name' => 'eyes',
'last_name' => '++'
];
return Db::table('employees')->insert($data);
}
}
如果你添加一个不存在的字段数据,会抛出一个异常 Exception,如果想强行新增抛弃不存在的字段数据,则使用 strick(false)方法,忽略异常:
return Db::table('employees')->strict(false)->insert($data);
我采用的数据库是 mysql,可以支持 replace 写入,insert 和 replace 写入的区别,前者遇到表中存在主键相同则报错,后者则修改。另外,使用 insertGetId()方法,可以在新增成功后返回当前数据 ID
批量数据新增
使用 insertAll()方法,可以添加二维数组批量新增数据,但要保持数组结构一致,成功则返回增加的行数
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$data =[
[
'employee_id' => '98',
'first_name' => '虚哥',
'last_name' => 'xx'
],
[
'employee_id' => '97',
'first_name' => '鸡哥',
'last_name' => 'jj'
]
];
return Db::table('employees')->insertAll($data);
}
}
如果是mysql数据库则可以使用replay()批量添加或修改:
return Db::table('employees')->replay()->insertAll($data);
如果批量插入的数据比较多,可以指定分批插入,使用limit方法指定每次插入的数量限制:
//分批次写入,每次最多100条数据
Db::table('employees')
->replay()
->limit(100)
->insertAll($data);
save()新增
save()方法是一个通用方法,可以自行判断是新增还是修改(更新)数据,判断的依据是是否存在主键,不存在即新增。用法如insert,此处略。
3) 更新数据
更新数据可以使用save()方法或者update()方法,如果修改数据包括了主键信息,则可以省略where条件
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$data =[
'first_name' => '东哥',
'last_name' => 'hh'
];
return Db::table('employees')
->where('employee_id', 97)
->save($data);
// 支持使用data方法传入要更新的数据,如果update方法和data方法同时传入更新数据,则以update方法为准。
// return Db::table('employees')
// ->where('employee_id', 97)
// ->data($data)
// ->save();
}
}
如果要更新的数据需要使用SQL函数或者其它字段,可以使用下面的方式:
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
return Db::table('employees')
->where('employee_id', 99)
->exp('first_name', 'UPPER(first_name)')
->update();
}
}
可以使用inc/dec方法自增或自减一个字段的值( 如不加第二个参数,默认步长为1)。
// score 字段加 1
Db::table('employees')
->where('employee_id', 1)
->inc('salary')
->update();
// score 字段加 5
Db::table('employees')
->where('employee_id', 1)
->inc('salary', 5)
->update();
// score 字段减 1
Db::table('employees')
->where('employee_id', 1)
->dec('salary')
->update();
// score 字段减 5
Db::table('employees')
->where('employee_id', 1)
->dec('salary', 5)
->update();
4) 删除数据
- 极简删除可以根据主键直接删除,删除成功返回影响行数,否则 0;
Db::table('employees')->delete(100);
- 根据主键,还可以删除多条记录;
Db::table('employees')->delete([97,98,99]);
- 正常情况下,通过 where()方法来删除;
Db::table('employees')->where('id', 100)->delete();
- 通过 true 参数删除数据表所有数据
Db::table('employees')->delete(true);
一般情况下,业务数据不建议真实删除数据,系统提供了软删除机制(模型中使用软删除更为方便),useSoftDelete方法表示使用软删除,并且指定软删除字段为delete_time,写入数据为当前的时间戳。。
// 软删除数据 使用delete_time字段标记删除
Db::table('employees')
->where('id', 100)
->useSoftDelete('delete_time',time())
->delete();
5) 查询表达式
查询表达式支持大部分的SQL查询语法,也是ThinkPHP查询语言的精髓,查询表达式的使用格式:where('字段名','查询表达式','查询条件')
。除了where方法外,还可以支持whereOr,用法是一样的。为了更加方便查询,大多数的查询表达式都提供了快捷查询方法。
表达式 | 含义 | 快捷查询方法 |
---|---|---|
= | 等于 | |
<> | 不等于 | |
> | 大于 | |
>= | 大于等于 | |
< | 小于 | |
<= | 小于等于 | |
[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] BETWEEN TIME | 时间区间比较 | whereBetweenTime |
> TIME | 大于某个时间 | whereTime |
< TIME | 小于某个时间 | whereTime |
>= TIME | 大于等于某个时间 | whereTime |
<= TIME | 小于等于某个时间 | whereTime |
EXP | 表达式查询,支持SQL语法 | whereExp |
find in set | FIND_IN_SET查询 | whereFindInSet |
比较查询
- 查询表达式支持大部分常用的 SQL 语句,语法格式如下:
where('字段名','查询表达式','查询条件');
- 在查询数据进行筛选时,我们采用 where()方法,比如 id=80;
Db::name('user')->where('id', 80)->find();
Db::name('user')->where('id','=',80)->find();
- 使用<>、>、<、>=、<=可以筛选出各种符合比较值的数据列表;
Db::name('user')->where('id','>',80)->select();
区间查询
- 使用 like 表达式进行模糊查询;
Db::name('user')->where('email','like','xiao%')->select();
- like 表达式还可以支持数组传递进行模糊查询;
Db::name('user')->where('email','like',['xiao%','wu%'], 'or')->select();
SELECT * FROM tp_user WHERE (email LIKE xiao% OR email LIKE 'wu%')
- like 表达式具有两个快捷方式 whereLike()和 whereNoLike();
Db::name('user')->whereLike('email','xiao%')->select();
Db::name('user')->whereNotLike('email','xiao%')->select();
- between 表达式具有两个快捷方式 whereBetween()和 whereNotBetween();
Db::name('user')->where('id','between','19,25')->select();
Db::name('user')->where('id','between',[19, 25])->select();
Db::name('user')->whereBetween('id','19,25')->select();
Db::name('user')->whereNotBetween('id','19,25')->select();
- in 表达式具有两个快捷方式 whereIn()和 whereNotIn();
Db::name('user')->where('id','in', '19,21,29')->select();
Db::name('user')->where('id','in', [19, 21, 29])->select();
Db::name('user')->whereIn('id','19,21,29')->select();
Db::name('user')->whereNotIn('id','19,21,29')->select();
- null 表达式具有两个快捷方式 whereNull()和 whereNotNull();
Db::name('user')->where('uid','null')->select();
Db::name('user')->where('uid','not null')->select();
Db::name('user')->whereNull('uid')->select();
Db::name('user')->whereNotNull('uid')->select();
EXP查询
EXP表达式支持更复杂的查询:
Db::name('user')->where('id','in','1,3,8')->select();
可以改成:
Db::name('user')->where('id','exp',' IN (1,3,8) ')->select();
exp查询的条件不会被当成字符串,所以后面的查询条件可以使用任何SQL支持的语法,包括使用函数和字段名称。因此推荐使用whereExp方法查询。
Db::name('user')->whereExp('id', 'IN (1,3,8) ')->select();
三:查询构造器(链式)
1).查询规则
- 前面课程中我们通过指向符号“->”多次连续调用方法称为:链式查询
- 当 Db::name(‘user’)时,返回查询对象(Query),即可连缀数据库对应的方法
- 而每次执行一个数据库查询方法时,比如 where(),还将返回查询对象(Query)
- 只要还是数据库对象,那么就可以一直使用指向符号进行链式查询
- 再利用 find()、select()等方法返回数组(Array)或数据集对象(Colletion)
- 而 find()和 select()是结果查询方法(放在最后),并不是链式查询方法
Db::name('user')->where('id', 27)->order('id', 'desc')->find()
- 除了查询方法可以使用链式连贯操作,CURD 操作也可以使用(后续课程研究)
2).更多查询
- 如果多次使用数据库查询,那么每次静态创建都会生成一个实例,造成浪费;
- 我们可以把对象实例保存下来,再进行反复调用即可;
$userQuery = Db::name('user');
$dataFind = $userQuery->where('id', 27)->find();
$dataSelect = $userQuery->select();
- 当同一个对象实例第二次查询后,会保留第一次查询的值;
$data1 = $userQuery->order('id', 'desc')->select();
$data2 = $userQuery->select();
return Db::getLastSql();
SELECT * FROM tp_user ORDER BY id DESC
- 使用 removeOption()方法,可以清理掉上一次查询保留的值;
$userQuery->removeOption('where')->select();
3). 链式查询方法
where
- 表达式查询,即where()方法的基础查询方式
$result=Db::table('employees')->where('salary', '<', '10000')->select();
- 关联数组查询,通过键值对来数组键值对匹配的查询方式
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->where([
'job_id' => 'IT_PROG',
'salary' => 6000
])
->select();
return json($result);
}
}
- 索引数组查询,通过数组里的数组拼装方式来查询
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->where([
['employee_id', '<', 110],
['salary', '<', 10000]
])
->select();
return json($result);
}
}
- 将复杂的数组组装后,通过变量传递,将增加可读性
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$map[] = ['employee_id', '<', 110];
$map[] = ['salary', 'in', [6000, 4200, 24000]];
$result=Db::table('employees')
->where($map)
->select();
return json($result);
}
}
- 字符串形式传递,简单粗暴的查询方式,whereRaw()支持复杂字符串格式,也支持SQL预处理模式
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->whereRaw("employee_id<110 AND salary IN (24000, 6000, 4200)")
->select();
return json($result);
}
}
field
- 使用 field()方法,可以指定要查询的字段
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->where('employee_id', '<', 105)
->field('employee_id, first_name, salary')
// ->field(['employee_id', 'first_name', 'salary']) 或者这种数组形式
->select();
return json($result);
}
}
- 使用 field()方法,给指定的字段设置别名
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->where('employee_id', '<', 105)
->field('employee_id as id, first_name as name, salary as 薪水')
->select();
return json($result);
}
}
- 在 fieldRaw()方法里,可以直接给字段设置 MySQL 函数
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->where('employee_id', '<', 105)
->field('job_id, LENGTH(job_id)')
->select();
return json($result);
}
}
- 使用 field(true)的布尔参数,可以显式的查询获取所有字段,而不是*
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->where('employee_id', '<', 105)
->field(true)
->select();
return json($result);
}
}
- 使用 withoutField()方法中字段排除,可以屏蔽掉想要不显示的字段
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->where('employee_id', '<', 105)
->withoutField('email, phone_number')
->select();
return json($result);
}
}
- 使用 field()方法在新增时,验证字段的合法性
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->where('employee_id', '<', 105)
->field('employee_id, first_name, last_name')
->insert([
'first_name' => '济钢',
'last_name' => 'aa'
]);
return json($result);
}
}
alias
使用 alias()方法,给数据库起一个别名:
limit
- 使用 limit()方法,限制获取输出数据的个数
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->field('employee_id, last_name')
->limit(5)
->select();
return json($result);
}
}
- 分页模式,即传递两个参数,比如从第 3 条开始显示 5 条 limit(2,5)
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->field('employee_id, last_name')
->limit(2, 5)
->select();
return json($result);
}
}
page
page()分页方法,优化了 limit()方法,无须计算分页条数
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->field('employee_id, last_name')
->page(2, 5) // 每页显示五条,第二页
->select();
return json($result);
}
}
order
- 使用 order()方法,可以指定排序方式,没有指定第二参数,默认 asc
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->field('employee_id, last_name, salary')
->order('salary', 'desc')
->select();
return json($result);
}
}
- 支持数组的方式,对多个字段进行排序
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->field('employee_id, last_name, salary')
// 按工资升序,工资相同则按员工编号降序
->order([
'salary' => 'asc',
'employee_id' => 'desc'
])
->select();
return json($result);
}
}
- 使用 orderRaw()方法,支持排序的时候指定 MySQL 函数
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->field('employee_id, last_name, salary')
->orderRaw('length(first_name) DESC')
->select();
return Db::getLastSQL();
}
}
group
- 使用 group()方法,给性别不同的人进行 price 字段的总和统计
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->field('job_id, SUM(salary)')
->group('job_id')
->select();
return json($result);
}
}
- 也可以进行多字段分组统计
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->field('job_id, manager_id, SUM(salary)')
->group('job_id, manager_id')
->select();
return json($result);
}
}
having
使用 group()分组之后,再使用 having()进行筛选
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$result=Db::table('employees')
->field('job_id, manager_id, SUM(salary)')
->group('job_id, manager_id')
->having('SUM(salary)>10000')
->select();
return json($result);
}
}
四:查询构造器(进阶)
1) 聚合查询
在应用中我们经常会用到一些统计数据,例如当前所有(或者满足某些条件)的用户数、所有用户的最大积分、用户的平均成绩等等,ThinkPHP为这些统计操作提供了一系列的内置方法,包括以下部分:
方法 | 说明 |
---|---|
count | 统计数量,参数是要统计的字段名(可选) |
max | 获取最大值,参数是要统计的字段名(必须) |
min | 获取最小值,参数是要统计的字段名(必须) |
avg | 获取平均值,参数是要统计的字段名(必须) |
sum | 获取总分,参数是要统计的字段名(必须) |
- 使用 count()方法,可以求出所查询数据的数量
Db::name('user')->count();
- count()可设置指定 id,比如有空值(Null)的 uid,不会计算数量;
Db::name('user')->count('uid');
- 使用 max()方法,求出所查询数据字段的最大值;
Db::name('user')->max('price');
- 如果 max()方法,求出的值不是数值,则通过第二参数强制转换;
Db::name('user')->max('price', false);
- 使用 min()方法,求出所查询数据字段的最小值,也可以强制转换;
Db::name('user')->min('price');
- 使用 avg()方法,求出所查询数据字段的平均值;
Db::name('user')->avg('price');
- 使用 sum()方法,求出所查询数据字段的总和;
Db::name('user')->sum('price');
2) 分页查询
3) 时间查询
传统方式
- 可以使用>、<、>=、<=来筛选匹配时间的数据;
Db::name('user')->where('create_time', '>', '2018-1-1')->select();
- 可以使用 between 关键字来设置时间的区间
Db::name('user')->where('create_time', 'between', ['2018-1-1', '2019-12-31'])->select();
Db::name('user')->where('create_time', 'not between', ['2018-1-1', '2019-12-31'])->select();
快捷方式
- 时间查询的快捷方法为 whereTime(),直接使用>、<、>=、<=;
Db::name('user')->whereTime('create_time', '>', '2018-1-1')->select();
- 快捷方式也可以使用 between 和 not between;
Db::name('user')->whereBetween('create_time', ['2018-1-1', '2019-12-31'])->select();
- 还有一种快捷方式为:whereBetweenTime()和 whereNotBetweenTime();
Db::name('user')->whereBetweenTime('create_time', '2018-1-1', '2019-12-31')->select();
- 默认的大于>,可以省略;
Db::name('user')->whereTime('create_time', '2018-1-1')->select();
固定查询
- 使用 whereYear 查询今年的数据、去年的数据和某一年的数据
Db::name('user')->whereYear('create_time')->select();
Db::name('user')->whereYear('create_time', 'last year')->select();
Db::name('user')->whereYear('create_time', '2016')->select();
- 使用 whereMonth 查询当月的数据、上月的数据和某一个月的数据
Db::name('user')->whereMonth('create_time')->select();
Db::name('user')->whereMonth('create_time', 'last month')->select();
Db::name('user')->whereMonth('create_time', '2016-6')->select();
- 使用 whereDay 查询今天的数据、昨天的数据和某一个天的数据
Db::name('user')->whereDay('create_time')->select();
Db::name('user')->whereDay('create_time', 'last day')->select();
Db::name('user')->whereDay('create_time', '2016-6-27')->select();
其它查询
- 查询指定时间的数据,比如两小时内的
Db::name('user')->whereTime('create_time', '-2 hours')->select();
- 查询两个时间字段时间有效期的数据,比如会员开始到结束的期间
Db::name('user')->whereBetweenTimeField('start_time', 'end_time')->select();
4) 高级查询
快捷查询
快捷查询方式是一种多字段相同查询条件的简化写法,可以进一步简化查询条件的写法,在多个字段之间用|分割表示OR查询,用&分割表示AND查询,可以实现下面的查询,例如:
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
Db::table('employees')
->where('first_name|last_name', 'like', '%a%')
->where('employee_id&manager_id', '>', 103)
->select();
return Db::getLastSql();
}
}
闭包查询
<?php
namespace app\controller;
use think\facade\Db;
class DbTest
{
public function index()
{
$jobId='IT_PROG';
$salary=11000;
$res=Db::table('employees')->where(function ($query) use($jobId, $salary) {
$query->where('job_id', $jobId)
->whereOr('salary', '>', $salary);
})->select();
return json($res);
}
}
字符串条件查询
对于一些实在复杂的查询,也可以直接使用原生SQL语句进行查询,例如:
Db::table('think_user')
->whereRaw('id > 0 AND name LIKE "thinkphp%"')
->select();
为了安全起见,我们可以对字符串查询条件使用参数绑定,例如:
Db::table('think_user')
->whereRaw('id > :id AND name LIKE :name ', ['id' => 0, 'name' => 'thinkphp%'])
->select();
快捷方法
系统封装了一系列快捷方法,用于简化查询
方法 | 作用 |
---|---|
whereOr | 字段OR查询 |
whereXor | 字段XOR查询 |
whereNull | 查询字段是否为Null |
whereNotNull | 查询字段是否不为Null |
whereIn | 字段IN查询 |
whereNotIn | 字段NOT IN查询 |
whereBetween | 字段BETWEEN查询 |
whereNotBetween | 字段NOT BETWEEN查询 |
whereLike | 字段LIKE查询 |
whereNotLike | 字段NOT LIKE查询 |
whereExists | EXISTS条件查询 |
whereNotExists | NOT EXISTS条件查询 |
whereExp | 表达式查询 |
whereColumn | 比较两个字段 |
动态查询
查询构造器还提供了动态查询机制,用于简化查询条件
动态查询 | 描述 |
---|---|
whereFieldName | 查询某个字段的值 |
whereOrFieldName | 查询某个字段的值 |
getByFieldName | 根据某个字段查询 |
getFieldByFieldName | 根据某个字段获取某个值 |
// 根据邮箱(email)查询用户信息
$user = Db::table('user')
->whereEmail('thinkphp@qq.com')
->find();
// 根据昵称(nick_name)查询用户
$email = Db::table('user')
->whereNickName('like', '%流年%')
->select();
// 根据邮箱查询用户信息
$user = Db::table('user')
->getByEmail('thinkphp@qq.com');
// 根据昵称(nick_name)查询用户信息
$user = Db::table('user')
->field('id,name,nick_name,email')
->getByNickName('流年');
// 根据邮箱查询用户的昵称
$nickname = Db::table('user')
->getFieldByEmail('thinkphp@qq.com', 'nick_name');
// 根据昵称(nick_name)查询用户邮箱
$email = Db::table('user')
->getFieldByNickName('流年', 'email');
5) 子查询
使用 fetchSql()方法,可以设置不执行 SQL,而返回 SQL 语句,默认 true;
Db::name('user')->fetchSql(true)->select();
使用 buildSql()方法,也是返回 SQL 语句,不需要再执行 select(),且有括号
Db::name('user')->buildSql(true);
结合以上方法,我们实现一个子查询:
$subQuery = Db::table('think_user')
->field('id,name')
->where('id', '>', 10)
->buildSql();
Db::table($subQuery . ' a')
->where('a.name', 'like', 'thinkphp')
->order('id', 'desc')
->select();
子查询还有闭包模式,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();
6) 原生查询
注意:V6.0.3+版本开始,原生查询仅支持Db类操作,不支持在模型中调用原生查询方法(包括query和execute方法)。
Db类支持原生SQL查询操作,主要包括query方法和execute方法
query方法用于执行SQL查询操作,返回查询结果数据集(数组)。
Db::query("select * from think_user where status=:id", ['id' => 1]);
execute用于更新和写入数据的sql操作,如果数据非法或者查询错误则返回false,否则返回影响的记录数。
Db::execute("update think_user set name='thinkphp' where status=1");
支持在原生查询的时候使用参数绑定,包括问号占位符或者命名占位符,例如:
Db::query("select * from think_user where id=? AND status=?", [8, 1]);
// 命名绑定
Db::execute("update think_user set name=:name where status=:status", ['name' => 'thinkphp', 'status' => 1]);