[SQL]查詢中如何同時orderBy A欄&groupBy B欄?

更新於 2024/06/20閱讀時間約 9 分鐘

最近遇到一個需求是要更改排序的邏輯,原本想像應該很簡單,但實作起來卻出乎意料之外的麻煩!

原本的撈取邏輯:要取得某學員user的在特定區間的學習中的課程,而排序則依課程編號course_set_id由大至小排序。

需求:排序要改依照課程學習的時間來排序(由近至遠)

乍看之下,原以為只要調整orderby的欄位即可,但卻忽略了原本的groupbyorderby都是course_set_id,因此如果此時要改成time這個欄位來排序,groupby 就需要多加上time 這個欄位才符合SQL規範。但加上後卻會對原本的資料結果產生巨大影響。


原query查詢如下:

/**
* 學員進行中的課程
* @param array $conditions
* @param string $result_type
* @param int $per
* @return LengthAwarePaginator|int|null
*/
public function getCourseLearnLogByUser($conditions, $result_type = 'paginate', $per = 8)
{
$result = CourseLearnLog::with(['course.courseSet'])
->whereHas('course.courseSet', function ($query) use ($conditions) {
$query->available();
})
->where('user_id', $conditions['user_id'])
->whereBetween('time', [$conditions['start_date'], $conditions['end_date']])
->groupBy('course_set_id')
->select(DB::raw('course_set_id as idSubChannel'));

switch ($result_type) {
case 'paginate':
return $result
->orderby('course_set_id', 'desc')
->paginate($per);
case 'count':
return $result
->get()
->count();
default:
return null;
}
}


Example:

原始資料:

course_set_id = 1, time = 2021-01-01 10:00:00

course_set_id = 1, time = 2021-01-01 12:22:33

course_set_id = 2, time = 2021-01-01 11:00:00


原本groupby.course_set_id最後的資料只會有兩筆:

course_set_id = 1 雖然有兩筆資料,但會被group起來,因此最後結果會是unique比數的course_set_id


但如果groupby.course_set_id, groupby.time兩個欄位的話,最後會有三筆

course_set_id + time兩個不一樣就會成一組,因此原始資料的3筆都會列入


解決方案

為了解決這個情況,因此想到了使用SubQuery,將同一堂課程的閱讀時間取最大值,之後再與MainQuery做join(以course_set_id 做關聯),並在MainQuery針對SubQuery的max_time做降冪排序,就可以免除用groupby的方式來處理!


調整後的query查詢如下:

/**
* 學員進行中的課程
* @param array $conditions
* @param string $result_type
* @param int $per
* @return LengthAwarePaginator|int|null
*/
public function getCourseLearnLogByUser($conditions, $result_type = 'paginate', $per = 8)
{
// SubQuery取得每個 course_set_id 的最後閱讀時間
$timeSubQuery = CourseLearnLog::query()
->whereBetween('time', [$conditions['rule']['start_date'], $conditions['rule']['end_date']])
->where('user_id', $conditions['user_id'])
->groupBy('course_set_id')
->select('course_set_id', DB::raw('MAX(time) AS max_time'));

$result = CourseLearnLog::with(['course.courseSet'])
->whereHas('course.courseSet', function ($query) use ($conditions) {
$query->available();
})
->joinSub($timeSubQuery, 'max_times', function ($join) {
$join->on('course_learn_logs.course_set_id', '=', 'max_times.course_set_id');
})
->whereBetween('time', [$conditions['start_date'], $conditions['end_date']])
->where('course_learn_logs.user_id', $conditions['user_id'])
->groupBy('course_learn_logs.course_set_id')
->select(DB::raw('course_learn_logs.course_set_id as idSubChannel'));

switch ($result_type) {
case 'paginate':
return $result
->orderBy('max_times.max_time', 'desc')
->paginate($per);
case 'count':
return $result
->get()
->count();
default:
return null;
}
}


avatar-img
46會員
30內容數
歡迎來到彼得的沙龍,在這裡,我將與你分享書籍精華的智慧、人際溝通的技巧、理財增值的秘訣,以及情緒管理的策略。不僅幫助你打好財務基礎,還能引領你在人生的每個環節中游刃有餘。如果你渴望成長,並追求更充實的生活,這裡就是你值得關注的空間。立即加入,與我一起探索成長的無限可能!
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
你可能也想看
Google News 追蹤
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
題目敘述 題目會給我們一張Employees 資料表。裡面分別有employee_id、name、reports_to 、age 等欄位。其中employee_id 是這張資料表的主鍵Primary key。 要求我們列出每一位經理人下轄部屬的數量和部屬的平均年齡(四捨五入到最接近的整數)。
Thumbnail
題目敘述 題目會給我們兩張資料表,第一張是Sales,第二張是Product。 第一張是Sales表格,裡面分別有sale_id、 product_id、year、quantity、price等欄位。其中(sale_id、 product_id)做為複合主鍵Primary key
Thumbnail
聚合函數 可以對資料的筆數、平均、最大、最小和加總的運算,提供查詢結果:如下表示: COUNT(Column):計算筆數,「*」是統計紀錄數。 AVG(Column):計算欄位平均值。 MAX(Column):計算欄位最大值。 MIN(Column):計算欄位最小值。 SUM(Colum
Thumbnail
多條件查詢 AND運算子 SELECT *​ FROM your_table_name WHERE column1 LIKE '_value1%' AND column2 = number​2 OR運算子 SELECT *​ FROM your_table_name WHERE colu
Thumbnail
查詢範圍 指定欄位 SELECT column1, column2, column3,... FROM your_table_name 不重複欄位 SELECT DISTINCT column1 FROM your_table_name 欄位別名 SELECT column1 A
Thumbnail
題目敘述 題目會給我們一張Customer資料表,裡面分別有id、name、referee_id 等欄位,其中id 是主鍵Primary Key。 要求我們列出所有推薦人ID referee_id不等於2的顧客,印出順序不拘。
Thumbnail
題目會給我們一張Products資料表,裡面分別有product_id、low_fats、recyclable等欄位,其中product_id 是主鍵Primary Key。 要求我們列出所有的可回收 且 低脂產品的product_id,順序不拘。
Thumbnail
參數化查詢是一種將參數值傳遞給SQL語句的技術,這些參數值不會被直接解釋為SQL語法。這樣可以防止惡意用戶通過在輸入中插入惡意的SQL語法來攻擊資料庫。參數化查詢的一個主要優點是它能夠提高安全性,同時也能夠幫助資料庫優化查詢。
Thumbnail
*合作聲明與警語: 本文係由國泰世華銀行邀稿。 證券服務係由國泰世華銀行辦理共同行銷證券經紀開戶業務,定期定額(股)服務由國泰綜合證券提供。   剛出社會的時候,很常在各種 Podcast 或 YouTube 甚至是在朋友間聊天,都會聽到各種市場動態、理財話題,像是:聯準會降息或是近期哪些科
Thumbnail
題目敘述 題目會給我們一張Employees 資料表。裡面分別有employee_id、name、reports_to 、age 等欄位。其中employee_id 是這張資料表的主鍵Primary key。 要求我們列出每一位經理人下轄部屬的數量和部屬的平均年齡(四捨五入到最接近的整數)。
Thumbnail
題目敘述 題目會給我們兩張資料表,第一張是Sales,第二張是Product。 第一張是Sales表格,裡面分別有sale_id、 product_id、year、quantity、price等欄位。其中(sale_id、 product_id)做為複合主鍵Primary key
Thumbnail
聚合函數 可以對資料的筆數、平均、最大、最小和加總的運算,提供查詢結果:如下表示: COUNT(Column):計算筆數,「*」是統計紀錄數。 AVG(Column):計算欄位平均值。 MAX(Column):計算欄位最大值。 MIN(Column):計算欄位最小值。 SUM(Colum
Thumbnail
多條件查詢 AND運算子 SELECT *​ FROM your_table_name WHERE column1 LIKE '_value1%' AND column2 = number​2 OR運算子 SELECT *​ FROM your_table_name WHERE colu
Thumbnail
查詢範圍 指定欄位 SELECT column1, column2, column3,... FROM your_table_name 不重複欄位 SELECT DISTINCT column1 FROM your_table_name 欄位別名 SELECT column1 A
Thumbnail
題目敘述 題目會給我們一張Customer資料表,裡面分別有id、name、referee_id 等欄位,其中id 是主鍵Primary Key。 要求我們列出所有推薦人ID referee_id不等於2的顧客,印出順序不拘。
Thumbnail
題目會給我們一張Products資料表,裡面分別有product_id、low_fats、recyclable等欄位,其中product_id 是主鍵Primary Key。 要求我們列出所有的可回收 且 低脂產品的product_id,順序不拘。
Thumbnail
參數化查詢是一種將參數值傳遞給SQL語句的技術,這些參數值不會被直接解釋為SQL語法。這樣可以防止惡意用戶通過在輸入中插入惡意的SQL語法來攻擊資料庫。參數化查詢的一個主要優點是它能夠提高安全性,同時也能夠幫助資料庫優化查詢。