Mysql實現先排序後分組的需求
阿新 • • 發佈:2018-12-21
在工作中做報表的時候,需要按建立時間排序,然後在對某些欄位進行分組排序。 首先遇到的問題是以前使用oracle資料庫時可以使用分組排序函式直接排序,由於切換到了Mysql資料庫,所以不能使用相同的解決方法。查詢相關資料後得出了一些靈感。oracle分組排序函式如下(複習下): Oracle中row_number()、rank()、dense_rank() 的區別: --row_number() 順序排序 1 2 3 4 5 --rank() 跳躍排序,如果有兩個第一級別時,接下來是第三級別 1 2 2 4 5 --dense_rank() 連續排序,如果有兩個第一級別時,接下來是第二級別 1 2 2 3 4 關於Parttion by: Parttion by關鍵字是Oracle中分析性函式的一部分,用於給結果集進行分割槽。它和聚合函式Group by不同的地方在於它只是將原始資料進行名次排列,能夠返回一個分組中的多條記錄(記錄數不變),而Group by是對原始資料進行聚合統計,一般只有一條反映統計值的結果(每組返回一條)。 總結: 在使用排名函式的時候需要注意以下三點: 1、排名函式必須有 OVER 子句。 2、排名函式必須有包含 ORDER BY 的 OVER 子句。 3、分組內從1開始排序。 TIPS: 使用rank over()的時候,空值是最大的,如果排序欄位為null, 可能造成null欄位排在最前面,影響排序結果。 (使用rank()/dense_rank() 時,必須要帶order by否則非法) 可以這樣: rank over(partition by course order by score desc nulls last)
Mysql的分組排序功能實現如下(我是按照兩個欄位進行分組的排序的):
select t.*,IF(@tmp=t.appr_node_name and @tmp1=t.stage,@rank:[email protected] + 1,@rank:=1) as rownum, @tmp:=t.appr_node_name as tmp, @tmp1 :=t.stage as tmp1 from (select rmt_work_appr_record.appr_record_id,rmt_work_appr_record.appr_node_id, rmt_work_appr_record.approver_name, rmt_work_appr_record.appr_node_name, rmt_work_appr_record.stage, rmt_work_appr_record.created_dt from rmt_work_appr_record where work_permit_id = 2000000004181 GROUP BY appr_node_id,approver_name,appr_node_name,stage ORDER BY created_dt) t; -- 按順序遍歷累計,順序非常重要,直接會影響查詢排序的正確性
效果如下:
可是這裡的建立時間欄位created_dt 並沒有按照原有的語義進行排序。查閱資料後知道Mysql按照先分組後排序的順序執行,所以最後的order by子句沒有生效。可以使用子查詢解決。
未分組的查詢結果如下:
可以看出分組排序並未按照建立時間的逆序查詢出相應的效果。於是嘗試先使用子查詢進行排序,然後再進行分組排序。
select t2.*,IF(@tmp=t2.appr_node_name and @tmp1=t2.stage,@rank:[email protected] + 1,@rank:=1) as rownum, @tmp:=t2.appr_node_name as tmp, @tmp1 :=t2.stage as tmp1 from ( select t.appr_record_id,t.appr_node_id, t.approver_name, t.appr_node_name, t.stage, t.created_dt from (select rmt_work_appr_record.appr_record_id,rmt_work_appr_record.appr_node_id, rmt_work_appr_record.approver_name, rmt_work_appr_record.appr_node_name, rmt_work_appr_record.stage, rmt_work_appr_record.created_dt from rmt_work_appr_record where work_permit_id = 2000000004181 ORDER BY created_dt desc) t GROUP BY t.appr_node_id,t.approver_name,t.appr_node_name,t.stage) t2;
先通過子查詢進行排序,然後再進行分組,最後使用臨時變數記錄分組排序的值:
現在就實現了先排序後分組排序的需求了。
參考資料:
分組排序
Mysql下實現先排序後分組