thinkphp的数据库操作(上)
如果想了解更多相关知识,可以前往我的个人博客看看: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 |
我们还可以调用Db::connect方法动态配置数据库连接信息,例如:
\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]);
thinkphp的数据库操作(上)相关推荐
- ThinkPHP6之数据库操作上
ThinkPHP6之数据库操作上 前言 1. 数据库配置 2. 数据库操作 1. 查询操作 2. 插入操作 3. 修改 4. 删除 5. 其他 3.数据集 总结 前言 注意,tp6在进行语法学习的时候 ...
- Node.js SQL数据库操作 (上)(操作MySQL数据库及 数据库连接池)
文章目录 Node.js MySQL驱动 操作 MySQL 数据库 连接 MySQL 数据库 增删改查操作 防止 SQL 注入攻击 数据库连接池操作 Node.js MySQL驱动 Node.js的原 ...
- thinkphp 5数据库操作
1.原生sql $options=Db::table('__MALL_POST__') ->alias('m') ->join('__MALL_CATEGORY_VALUE__ v','m ...
- 使用Memcache缓存mysql数据库操作的原理和缓存过程浅析
1.首先明确是不是一定要上缓存,当前架构的瓶颈在哪里,若瓶颈真是数据库操作上,再继续往下看. 2.明确memcached和redis的区别,到底要使用哪个.前者终究是个缓存,不可能永久保存数据(LRU ...
- thinkphp mysql操作数据库_thinkPHP数据库操作
thinkPHP如果要对数据库操作,一般来说首先要做的是在配置文件中链接数据库,然后用M方法实例化一张表,然后就是对表的操作了 可以开启调试功能查看程序执行的sql语句: 1.开启调试功能(默认是已经 ...
- ThinkPHP(7)——数据库操作
连接数据库 实例化模型 实例化基础模型 实例化自定义模型 实例化空模型 增删改查 add select update delete order排序 field字段选择 limit page分页 gro ...
- ThinkPHP自动化为已经上传的图片添加「 响应式」水印(数据库字段部分)
版权属于: Postbird - There I am , in the world more exciting! 原文地址: http://www.ptbird.cn/thinkphp-image- ...
- .ne中的控制器循环出来的数据如何显示在视图上_Web程序设计-ASP.NET MVC4数据库操作实例...
ASP.NET MVC4数据库操作实例 之前文章介绍了MVC4与Pure框架结合进行的网页设计过程中如何定义控制器.方法.模型.视图等.并使用实例进行了简单说明.本文将在此基础上进一步说明如何使用MV ...
- php读取excel中数据库,ThinkPHP 框架实现的读取excel导入数据库操作示例
本文实例讲述了ThinkPHP 框架实现的读取excel导入数据库操作.分享给大家供大家参考,具体如下: 入口文件中: require_once VENDOR_PATH.'PHPExcel/PHPEx ...
最新文章
- java时间操作方法Calendar
- linux操作小技巧
- 二维树状数组 BZOJ 1452 [JSOI2009]Count
- Fixed: MacOS Mojave(10.14) 解决终端用Crontab报权限问题(不管是Root还是普通用户)及Linux基础(shell)...
- 10.14.2 快捷键,环境变量等
- Elastic-Job配置步骤
- Jest + React Testing Library 单测总结
- java常用类介绍及源码阅读(LinkedList)
- 信号量进程同步与互斥
- jQuery中的ajax、jquery中ajax全局事件、load实现页面无刷新局部加载、ajax跨域请求jsonp、利用formData对象向服务端异步发送二进制数据,表单序列化(异步获取表单内容)
- python箴言_Python高效率编程的8条箴言
- Android UI库书签
- thinkphp6 redis并发解决处理方案
- 百度正用谷歌AlphaGo,解决一个比围棋更难的问题 | 300块GPU在燃烧
- python 搭建的http 动态服务器_Python3搭建http服务器的实现代码
- Asp.Net母版页元素ID不一致的体现
- table中background背景图片自动拉伸
- vfp 中调用硬盘_硬盘你真的选对了么?固态真的好用么?细数硬盘这些年出现的坑!...
- Ubuntu 18.04安装Apollo 6.0:从零开始到启动Demo(超多细节)
- 什么是CMPP、SGIP、SMGP三大运营商接口协议
热门文章
- java查询历史记录的思路_JavaWeb之商品查看后历史记录代码实现
- width:100vh有感而发
- 无限火力更新服务器公告,英雄联盟无限火力官网公告2021?无限火力怎么玩?...
- ucore操作系统总结
- BitTorrent一种内容分发协议
- spring集成quartz报org.springframework.scheduling.quartz.CronTriggerBean异常
- Python字符串转16进制数字
- 微信小程序的经验总结,UI组件、图表、自定义bar你学会了吗
- 博恩.崔西七步成功公式
- 微信小程序动态的显示或隐藏控件