在工作中做报表的时候,需要按创建时间排序,然后再对某些字段进行分组排序。
首先遇到的问题是以前使用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:=@rank + 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:=@rank + 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下实现先排序后分组