(1)问题描述
有时候我们需要对数据进行去重处理,例如查询结果里的文件名有重复,我们希望可以按照创建时间排序,最终结果里每个文件名只取创建时间最近的一个。
(2)有哪些问题
想到去重,可以想到使用distinct或者group by分组。但是这两者有个问题,例如我们查询结果中包含多个目标字段【文件id,文件名,文件所属项目,文件创建时间,文件类型】等等。
distinct是对组合进行去重,必须加在select中和所有目标字段之前,也就是只有当上面的5个字段都重复了,这条数据才算是重复。
group by也是要求select中的字段必须出现在group by中,同样是上面的5个字段都重复了,这条数据才算是重复。
而我们的目标是只根据【文件名】进行分组,在分组中根据文件创建时间进行排序,然后每组中只选取创建时间最近的那条数据,且这条数据是完整的包含上面5个字段。
(3)为什么不在业务代码里进行过滤处理?
因为还有分页查询的功能,所以查询的工作就必须得在sql里实现(就当学习sql了)
(1)当前sql
SELECT T.ID, R.TASK_ID, T.CRT_DT_TM, 'RST_TABLE' AS TYPE, T.FULL_NM AS NAME FROM period_script_x_rst_table T JOIN period_script_revision R ON R.ID = T.PERIOD_SCRIPT_REV_ID JOIN period_script_info S ON S.ID = R.PERIOD_SCRIPT_ID WHERE S.MASTER_REV_ID = T.PERIOD_SCRIPT_REV_ID
查询结果
可以看到NAME有很多重复的,我们只想取到时间最近的那一条,同时还不能用group by进行分组
(2)加上分组语句和组内排序
SELECT T.ID, R.TASK_ID, 'RST_TABLE' AS TYPE, T.FULL_NM AS NAME, rank () over ( partition BY T.FULL_NM ORDER BY T.CRT_DT_TM DESC ) rankNo FROM period_script_x_rst_table T JOIN period_script_revision R ON R.ID = T.PERIOD_SCRIPT_REV_ID JOIN period_script_info S ON S.ID = R.PERIOD_SCRIPT_ID WHERE S.MASTER_REV_ID = T.PERIOD_SCRIPT_REV_ID
查询结果
可以看到结果是根据NAME进行了分组,并且进行了组内排序,最后给每条数据加了一个组内排序序号。
(3)加上条件过滤实现组内取第一条目标数据
SELECT * FROM ( SELECT T.ID, R.TASK_ID, T.CRT_DT_TM, 'RST_TABLE' AS TYPE, T.FULL_NM AS NAME, rank () over ( partition BY T.FULL_NM ORDER BY T.CRT_DT_TM DESC ) rankNo FROM period_script_x_rst_table T JOIN period_script_revision R ON R.ID = T.PERIOD_SCRIPT_REV_ID JOIN period_script_info S ON S.ID = R.PERIOD_SCRIPT_ID WHERE S.MASTER_REV_ID = T.PERIOD_SCRIPT_REV_ID ) e WHERE e.rankNo = 1
查询结果
可以看到,根据组内排序序号rankNo=1来过滤,就实现了去重的效果
如果想要实现去重,而distinct和group by都无法满足需求,就可以考虑试试这个方案
rank() over(partition by e.commandid order by e.systemid desc) rankNo ( partition by 根据什么进行分组, order by 根据什么进行排序, rank() over() 进行排名 rankNo 别名 )