查询一个表,返回的结果中若某一字段有重复的行,只保留一行数据。(保留的数据要求是所有行中某一字段的最值)


例子:

表 score:

id time name math cs physics chemistry biology
1 2021-07-11 Lucy 80 90 34 45 43
2 2021-09-22 Lucy 77 89 54 56 67
3 2020-04-12 Kaven 87 34 34 26 87
4 2021-08-22 Hyke 65 78 34 56 67
5 2020-05-17 Kaven 78 97 67 97 56

目标是查询 score 中学生最近的一次成绩记录

查询结果理应如下:

id time name math cs physics chemistry biology
2 2021-09-22 Lucy 77 89 54 56 67
4 2021-08-22 Hyke 65 78 34 56 67
5 2020-05-17 Kaven 78 97 67 97 56

有两种方法可以进行查询:

  • 根据行号去重

    • 对表 score 分区后排序,取排序后的第 1 行数据

    • partition by关键字是分析性函数的一部分,它和聚合函数(如group by)不同的地方在于它能返回一个分组中的多条记录,而聚合函数一般只有一条反映统计值的记录,

      partition by用于给结果集分组,如果没有指定那么它把整个结果集作为一个分组。

      partition by 与group by不同之处在于前者返回的是分组里的每一条数据,并且可以对分组数据进行排序操作。后者只能返回聚合之后的组的数据统计值的记录。

    • 经典用法:ROW_NUMBER() OVER(partition by 分组列 order by 排序列)

    1
    2
    3
    select * from 
    (select *,row_number() over (partition by name order by time desc) Suquence from score) s
    where s.Suquence=1
  • group by 查询

    • 使用 group by 时,如果决定保留行的字段的值在表中是唯一的,则可以直接使用(如 id,假设 每个学生的数据在表中的 id 与时间的大小顺序一致,即时间越近,id 越大)

      1
      2
      select * from score where id in 
      (select max(id) from score group by name)
    • 但实际上假设是特殊的,一般情况 id 与字段大小无关联的话,需要多表查询

      1
      2
      3
      select a.* from score as a inner join
      (select max(time) as time,name from score group by name) as b
      on a.time=b.time and a.name=b.name