1. 需求
目前有这样两个需求:
1) 查询用户,显示用户的信息以及他写过的书籍。如果用户有书籍,则显示,最多显示2本。如果没有,则不显示书籍。
2) 显示用户的id号以及对应的书籍件数(只用SQL实现,不使用业务逻辑)。
2. 准备
本文中用到的user
模型,数据,控制器,路由之类的都已经在另一篇文章 手摸手教你让Laravel开发Api更得心应手 创建好了。
users
表中的数据
books
表中的数据
3. 关联查询限制条数
这个比较容易,只要在关联函数限制条数即可。
3.1. 创建Book模型
1 |
php artisan make:model Models/Book |
3.2. 添加关联函数并且限制条数
编辑 app/Models/User.php
,添加关联函数
1 |
public function books(){ |
3.3. 测试
在app/Http/Controllers/Api/UserController.php
里,随意添加一个测试函数
1 |
//关联查询限制条数 |
测试结果,符合要求,id为1的用户原来是3本书籍,现在只被取出2本。
4. 分组查询显示为零的结果
4.1. SQL语句
一开始,我们会这样写SQL
语句
1 |
select `u`.`id`,`u`.`name`,`u`.`num` from `users` as `u` left join (select `user_id`,count(*) as `num` from books group by `user_id`) as `b` on `u`.id = `b`.user_id |
最后显示如下,并不会将没有的显示为0
所以我们稍加修改,用上MySQL
的内置函数
1 |
select distinct `u`.`id`,`u`.`name`,IFNULL( `b`.`num`, 0 ) AS num from `users` as `u` left join (select `user_id`,count(*) as `num` from books group by `user_id`) as `b` on `u`.id = `b`.user_id |
符合我们的需求。
4.2. Laravel框架中使用
写SQL很容易,那我们应该如何在框架中使用呢(不允许查完再用业务逻辑后获得答案)?同时我们再附加一个条件,只要id为1
,2
,3
,4
,5
的用户。
4.2.1. 直接编写
查询Laravel手册,参考查询构造器
的高级join语句
,我们会立刻想到下面这样编写
1 |
public function test3(){ |
测试的时候我们发现报了错
1 |
Unknown column 'b.number' in 'field list' (SQL: select distinct u.id,IFNULL( b.number, 0 ) AS number from `users` as `u` left join `books` as `b` on `user_id` in (1, 2, 3, 4, 5) and `u`.`id` = `b`.`user_id` where `id` in (1, 2, 3, 4, 5)) |
最后的SQL语句跟我们想象中的不太一样。
4.2.2. 问题分析
错误的原因是,我们其实是使用left join
连接了子查询,但是Laravel
的联表查询,例如join
,lefeJoin
,rightJoin
等,经过个人的测试,这些闭包并不能实现子查询的。所以最后获得的SQL语句是错误的。
Laravel官方文档的子查询并没有这方面详细的介绍,所以我们一起来了解一下其他地方查来的资料
4.2.3. Query Builder
4.2.3.1. TOSQL()
toSql()
方法的作用是为了获取不带有binding
参数的SQL
例如:
1 |
select * from `users` where `users`.`id` = ? |
4.2.3.2. GETQUERY()
getQuery()
方法的作用是为了获取binding
参数并代替toSql()
获得SQL
的问号,从而得到完整的SQL
例如:
1 |
select * from `users` where `users`.`id` = 1 |
4.2.4. 修复问题
现在我们使用Query Builder
来修复一下之前的问题
1 |
public function test2(){ |
4.2.5. 测试
最后的结果符合我们的需求
本文链接: https://www.guaosi.com/2019/03/19/laravel-with-limit-and-group-show-zero/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议
