select device_id, university, gpa
from (
    select device_id, university, gpa,
    row_number() over(partition by university order by gpa) as rn
    from user_profile
) as univ_min
where rn=1
order by university;

开窗函数(Window Functions),也叫窗口函数分析函数,是 SQL 中用于在不减少行数的前提下进行复杂统计计算的强大工具。

它是普通聚合函数(GROUP BY)的升级版:

  • 普通聚合:多行变一行(分组后,原始数据没了)。
  • 开窗函数:多行算一值,原始行还在(每行后面多挂一个统计结果)。

开窗函数分几类?

① 排名类 (Ranking Functions)

用于给数据行进行排序和编号。

  • ROW_NUMBER(): 连续行号(1, 2, 3, 4...),即使值相同也不重复。
  • RANK(): 跳跃排名(1, 1, 3, 4...),值相同名次相同,后续名次跳过。
  • DENSE_RANK(): 密集排名(1, 1, 2, 3...),值相同名次相同,后续名次不跳过。
  • NTILE(n): 将数据均匀分成 n 个桶(如前 20%)。
  • PERCENT_RANK(): 相对排名百分比。

② 聚合类 (Aggregate Functions)

将普通的聚合函数变成开窗用,保留原行数

  • SUM()COUNT()AVG()MAX()MIN()
  • 用法区别:普通聚合是 GROUP BY 后多行变一行;开窗聚合是每行后面挂一个统计值。

③ 偏移类 (Value Functions)

用于访问当前行“前面”或“后面”的数据。

  • LAG(col, n): 取当前行往前数第 n 行的值。
  • LEAD(col, n): 取当前行往后数第 n 行的值。
  • FIRST_VALUE(col): 取窗口内第一行的值。
  • LAST_VALUE(col): 取窗口内最后一行的值(需注意范围定义)。

PARTITION BY 和 ORDER BY 哪个必须写?

结论:

  • PARTITION BY永远不是必须的(可选)。如果不写,默认整张表作为一个大窗口。

想分组就写,不想分组(全表算)就不写。永远可选

  • ORDER BY取决于你用什么函数对于 排名类 和 前后取值类:必须写(否则逻辑无意义)。

对于 聚合类:可选(写不写含义不同)。