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 許可協議
