【三】Tp常见的辅助方法
原生SQL语句里除了目前所使用的基本操作增删改查,还有类似于group、where、order、limit等这样的字句。
ThinkPHP封装了相应的子句方法:封装的方法都在父类模型Model.class.php
where 表示限制查询的条件
limit 限制输出的条数
filed 限制输出的字段,也就是select id,name,age等类似语句
注意:下面两个方法在父类模型中不存在,方法不存在会走魔术方法__call(),利用__call()方法实现一些特殊的Model方法,而group和order在链操作方法列表,经过__cal()方法调用。实现相应方法。除此外还有alias(别名),having(限制查询条件),distinct(去重),filter(过滤)。
order 字段排序
group 按照指定字段进行分组查询
下面依次介绍:
(1)where
作用:限制查询条件
原生sql语句:select 字段 from 表名 where 条件;
ThinkPHP中封装的where方法:
$model -> where(条件表达式);//ThinkPHP条件表达式支持字符串形式('id=1'),也支持数组形式(array(id=>'1')),推荐使用字符串形式 $model -> CURD操作;
案例:使用where查询表中数据('id>20')
原生SQL语句:
select * from sp_dept where id>20;
ThinkPHP的where方法:
public function test(){
//实例化模型
$model = M('dept');
//where查询
$model -> where('id>20 and id<22');
//验证 dump($model);die;
$data = $model -> select();//这里可以不添加参数,上面输出$model验证下
dump($data);
}
验证$model输出如下:
["options":protected] => array(1) { ["where"] => array(1) { ["_string"] => string(5) "id>20 id<22" } }
底层父类模型:
// 分析表达式 $options = $this->_parseOptions($options);
跟踪信息的sql:SELECT * FROM `sp_dept` WHERE ( id>20 and id<22) [ RunTime:0.0000s ]
回顾:在MySQL里除了where外,having也可以限制查询
面试题:where和having都可以限制查询条件,区别是什么?
where表示限制查询条件,要求查询字段必须是数据表中存在的字段;而having要求结果集(查询出的数据结果)中存在的字段
(2)limit方法
限制输出的条数(典型应用,数据的分页)
原生SQL语句:
select 字段 from 表名 where 条件 limit 限制的条数;
ThinkPHP中封装的limit方法:
①$model -> limit(n); //n为大于0的数字,表示输出表中的前n行
②$model -> limit(起始位置,偏移量); //表示从起始位置开始,往后查询指定长度的记录数。实际使用中还支持$model -> limit('起始位置,偏移量')的写法
案例:使用limit实现查询表中的数据限制
①查询前n条
public function test(){
//实例化模型
$model = M('dept');
//限制记录
$model -> limit(2);//查询前2条
$data = $model -> select();
dump($data);
}
跟踪信息的SQL语句:SELECT * FROM `sp_dept` LIMIT 2 [ RunTime:0.0000s ]
②查询带偏移量的形式
public function test(){
//实例化模型
$model = M('dept');
//限制记录
$model -> limit(2,2);//查询从第三条开始的两条记录
$data = $model -> select();
dump($data);
}
跟踪信息SQL语句:SELECT * FROM `sp_dept` LIMIT 2,1 [ RunTime:0.0000s ]
注意:limit从0开始,所以如果想从第3条开始,传入2即可
(3)field方法
作用:限制输出的结果集字段
类似于:原生SQL的select id,name,age
语法:
$model -> field('字段1,字段2...字段n[as 别名,支持别名]'); //参数就是select之后from之前的一串字符串
案例:限制结果集输出,只显示id,name信息
原生sql:
select id,name from sp_dept;
ThinkPHP封装的field方法:
public function test(){
//实例化模型
$model = M('dept');
//条件限制
$model -> where('id>20 and id<22');
//结果集记录限制
$model -> field('id,name');
//执行查询
$data = $model -> select();
dump($data);
}
跟踪信息SQL语句:SELECT `id`,`name` FROM `sp_dept` WHERE ( id>20 and id<22 ) [ RunTime:0.0010s ]
(4)order方法
作用:按照指定的字段进行指定规则排序
原生SQL语法里:
order by 字段 排序规则(升序ase/降序desc)
ThinkPHP封装的语法:
$model -> order('字段名 排序规则');
案例:使用order方法,查询部门表中数据,并且按照id进行降序排列
原生SQL语句
select * from sp_dept order by id desc;
ThinkPHP方法
public function test(){
//实例化模型
$model = M('dept');
$model -> where('id>20');
//按照id降序排序
$model -> order('id desc');
//查询
$data = $model -> select();
dump($data);
}
跟踪信息SQL语句:SELECT * FROM `sp_dept` WHERE ( id>20 ) ORDER BY id desc [ RunTime:0.0000s ]
(5)group方法
作用:用于分组查询
ThinkPHP封装的group方法
$model -> group('字段名');//按照字段名进行分组,相当于group by 字段名
案例:查询部门表,查询出部门名称和出现的次数
原生SQL
select name,count(*) as count from sp_dept group by name;
ThinkPHP的group辅助方法
因为上面使用了限制字段和分组查询,所以只靠group方法,无法实现。需要配合field方法配合
public function test(){
//实例化模型
$model = M('dept');
//指定字段和分组
$model -> group('name');
$model -> field('name,count(*) as count');
// dump($model);die;
//查询
$data = $model -> select();
dump($data);
}
输出结果:
array(3) { [0] => array(2) { ["name"] => string(4) "tony" ["count"] => string(1) "1" } [1] => array(2) { ["name"] => string(9) "技术部" ["count"] => string(1) "3" } [2] => array(2) { ["name"] => string(9) "新天剑" ["count"] => string(1) "2" } }
跟踪信息SQL语句:SELECT `name`,count(*) as count FROM `sp_dept` GROUP BY name [ RunTime:0.0010s ]
【四】连贯操作
(1)简介
将辅助方法全部写在一行上的写法为连贯操作
语法:$model -> where() -> limit() ->order() -> field() -> select{}
中间标红的即为辅助方法
辅助方法顺序:在连贯操作里,没有顺序要求。只要模型在头部,CURD方法在尾部即可
案例:连贯操作改写
public function test(){
//实例化模型
$model = M('dept');
//连贯操作查询
$data = $model -> field('name,count(*) as count') ->group('name')-> select();
dump($data);
}
问题:为什么辅助方法可以写在一行上?
查看分析父类模型,例如field()返回的都是对象本身$model
/**
* 指定查询字段 支持字段排除
*/
public function field($field,$except=false){
if(true === $field) {// 获取全部字段
$fields = $this->getDbFields();
$field = $fields?:'*';
}elseif($except) {// 字段排除
if(is_string($field)) {
$field = explode(',',$field);
}
$fields = $this->getDbFields();
$field = $fields?array_diff($fields,$field):$field;
}
$this->options['field'] = $field;
return $this;
}
原因就是每一个辅助方法最后的返回值都是$this,而$this是指当前模型类。由模型类去调用后续的辅助方法,这个是行得通的。
之所以将select()等具体的CURD操作方法放到最后,是因为它返回的是数组结果集 ,结果集无法调用辅助方法。所以CURD操作必须放到最后
注意:开发过程里都会遵循使用连贯操作的形式来替代单个辅助方法的写法,优点可读性高
【五】Tp中的统计查询
ThinkPHP中系统封装了以下几个查询方法的使用,方便后期统计的使用。以下几个查询方法在父类模型中不存在,都是由魔术方法__call()生成的
包含count(),max(),min(),avg(),sum()
(1)count() 查询表中总的记录数(有where时表示查询指定条件的记录数)
(2)max() 查询某个字段的最大值
(3)min() 查询某个字段的最小值
(4)avg() 查询某个字段的平均值
(5)sum() 查询某个字段的总和
下面依次介绍
(1)count()
语法:$model -> [where() ->]count; where可选
public function test(){ //实例化模型 $model = M('dept'); $count = $model->count(); dump($count);//返回字符形式的记录总数 }
跟踪信息的sql语句:SELECT COUNT(*) AS tp_count FROM `sp_dept` LIMIT 1 [ RunTime:0.0010s ]
(2)max()
语法:$model->max('字段名');查询指定字段名的最大值
注意:开发中常用来查找最后一个会员注册id
案例:
public function test(){ //实例化模型 $model = M('dept'); $count = $model->max('id'); dump($count);//返回字符形式 }
跟踪信息SQL:SELECT MAX(id) AS tp_max FROM `sp_dept` LIMIT 1 [ RunTime:0.0010s ]
(3)min()
语法:$model->min('字段名'); 指定字段的最小值
注意:实际开发里常用来查询最早注册的会员id
案例:
public function test(){ //实例化模型 $model = M('dept'); $count = $model->min('id'); dump($count);//返回字符形式字符值 }
跟踪信息SQL值:SELECT MIN(id) AS tp_min FROM `sp_dept` LIMIT 1 [ RunTime:0.0000s ]
(4)avg()
语法:$model -> avg('字段名'); 查询字段平均值
public function test(){ //实例化模型 $model = M('dept'); $count = $model->avg('id'); dump($count);//返回字符形式,并保留4位小数 }
跟踪信息SQL:SELECT AVG(id) AS tp_avg FROM `sp_dept` LIMIT 1 [ RunTime:0.0000s ]
(5)sum
语法:$model -> sum('字段名'); 查询某个字段的总和
public function test(){ //实例化模型 $model = M('dept'); $count = $model->sum('id'); dump($count);//返回字符形式字段总和 }
跟踪信息SQL:SELECT SUM(id) AS tp_sum FROM `sp_dept` LIMIT 1 [ RunTime:0.0000s ]
【六】拓展:fetchSql
之前介绍了sql调试的方法getLastSql(别名_sql),但是该方法要求最后一条成功执行的sql,如果拿着个方法来调试sql,只能调试逻辑错误,不能调试语法错误。
所以出现了建立在连贯操作上的fetchSql方法
语法:$model ->where() -> limit() -> order() -> fetchSql(true) -> CURD操作
位置:fetchSql()可以看做是一个辅助方法,所以可以放到模型后,CURD操作之前任意位置。
例如:$model->where()->limit()->order()->fetchSql(true)->CURD操作
版本要求:必须是3.2.3版本之后才可以用
与getLastSql区别:返回值不同,且不会执行sql语句,只会返回sql语句。而getLastSql会返回并执行sql语句
public function test(){ //实例化模型 $model = M('dept'); $count = $model->field('name,count(*) as count') ->group('name')->fetchSql(true)->select(); dump($count);//返回sql语句SELECT `name`,count(*) as count FROM `sp_dept` GROUP BY name
}
跟踪信息SQL没有显示,说明没有被执行,只是被返回(因为没有被执行,所以即使语法错误也不会执行,都将会返回sql语句)。