1. 程式人生 > >mysql分組後group_concat()的使用場景總結

mysql分組後group_concat()的使用場景總結

現有這樣一個業務場景,在一個教務系統中,統計某個學生在某一次考試中的各科成績與各科成績的年級排名與班級排名?
假設表結構如下:

這裡寫圖片描述

最直白的做法是先統計出該學生的考試成績,在通過他考試的那麼科目再去查他所在班級與年級的排名;但是每個科目都要進行一次查詢,意味著要迴圈科目去進行查詢,影響效率。
如果我們讓科目分組代替迴圈該學生考試的科目去查詢就可以省去很多次查詢,意思是一次就取出所有科目的班級排名或年級排名,思路如下:
1.在這一場考試中先以科目為第一排序,分數為第二排序,得到相同科目分數連續並且倒序排列的資料:

SELECT score,studentid,SUBJECT FROM
zhihui_test_score WHERE testid=171 AND classid=160 AND grade=2 AND term=1 AND xjid=55 ORDER BY SUBJECT DESC,score DESC

假設得到以下資料結果:

這裡寫圖片描述

2.假設我們現在是studentid為“1184”的學生,我們現在要做的就是按照科目分組,獲得studentid和score都以score倒序排列的集合列表,這時候我們就要用上mysql的group_concat()函式來獲得分組的後的列值,並且都以score來排序,整合兩條SQL就是這樣:

SELECT  SUBJECT, GROUP_CONCAT(score ORDER
BY score DESC) myScore, GROUP_CONCAT(studentid ORDER BY score DESC) studentid FROM ( SELECT score,studentid,SUBJECT FROM zhihui_test_score WHERE testid=171 AND classid=160 AND grade=2 AND term=1 AND xjid=55 ORDER BY SUBJECT DESC,score DESC ) AS scoreOrder GROUP BY SUBJECT ORDER BY score DESC

最後得到的結果就是科目分組後的各個學生ID以分數排序的集合,從而來繼續後面的班級或者年級排名的邏輯(從集合中找到當前學生ID出現的次序是多少)
這裡寫圖片描述

我們可以很直白的看出當前“1184”學生對應的“75”學科的班級排名是第四,“76”學科的班級排名是第二了。

場景二:

現在我們要對某種商品的訂單進行管理,需要顯示每個訂單的最近的一次操作的日誌資訊,假設訂單日誌表如下:

這裡寫圖片描述

現在我們需要的就是以每個訂單分組後獲取最近的一次操作資訊,比較類似與第一個例子,我們以插入的ID或者建立的時間來倒序,再擷取通過group_concat()連線的各個值的第一個值就可以了:

SELECT order_id,SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY id DESC),',',1) id,
SUBSTRING_INDEX(GROUP_CONCAT(memo ORDER BY id DESC),',',1) memo,
SUBSTRING_INDEX(GROUP_CONCAT(`data` ORDER BY id DESC),',',1) `data` 
FROM `purchase_order_logs` GROUP BY order_id;

查詢結果如下
這裡寫圖片描述

總結:
使用函式:group_concat() 分組後獲取各行的值,內部可排序;
substring_index()按關鍵字擷取字串
說明:substring_index(被擷取欄位,關鍵字,關鍵字出現的次數)
場景一:分組後需要得到某一個值所在分組中的順序;
場景二:分組後需要返回一個特定的值。
(注:mysql版本為5.7 場景一種5.5的版本只排一個欄位也可以完成對應的排序順序)