SQL核心函数
聚合函数:SUM/AVG/MAX/MIN/COUNT实现数据汇总,GROUP BY分组后HAVING过滤组级结果。注意COUNT(*)包含NULL,COUNT(列)忽略NULL。
窗口函数:通过OVER子句实现高级分析,包含五大类:
- 排名函数:ROW_NUMBER/RANK/DENSE_RANK
- 取值函数:LAG/LEAD获取相邻行,FIRST_VALUE取首项
- 分片函数:NTILE数据分桶
- 聚合窗口:SUM/AVG实现滚动累计
- 偏移分析:同比环比计算
关键区别:聚合函数压缩行数,窗口函数保留原数据行数。执行顺序上窗口函数在GROUP BY之后处理。
📊 昨日回顾 - 复习笔记
一、聚合函数
核心语法
sql
SELECT
字段,
聚合函数(列) AS 别名
FROM 表
WHERE 行级过滤条件
GROUP BY 分组字段
HAVING 组级过滤条件(可使用聚合函数)
ORDER BY 排序字段;
聚合函数一览
| 函数 | 作用 | 空值处理 |
|---|---|---|
SUM(列) |
求和 | 忽略NULL |
AVG(列) |
平均值 | 忽略NULL |
MAX(列) |
最大值 | 忽略NULL |
MIN(列) |
最小值 | 忽略NULL |
COUNT(列) |
计数 | 忽略NULL |
COUNT(*) |
总行数 | 包含NULL |
COUNT(1) |
总行数 | 包含NULL |
COUNT 的区别
sql
COUNT(字段) -- 排除NULL值,统计非空行数
COUNT(*) -- 统计所有行,包含NULL
COUNT(1) -- 统计所有行,性能略优于COUNT(*)
核心规则
| 规则 | 说明 |
|---|---|
| SELECT约束 | 非分组字段、非聚合值不能出现在SELECT中 |
| HAVING | 只用于聚合值过滤(如总薪资>10000) |
| WHERE | 用于行级过滤(如薪资>1000) |
| NULL处理 | 空值不参与聚合计算 |
二、窗口函数(开窗函数)
基础语法
sql
函数() OVER (PARTITION BY 分组字段 ORDER BY 排序字段)
五种窗口函数类型
| 类型 | 函数 | 用途 |
|---|---|---|
| 排名类 | ROW_NUMBER(), RANK(), DENSE_RANK() |
取TOP N |
| 取值类 | LAG(), LEAD(), FIRST_VALUE() |
同环比、上下行 |
| 分片类 | NTILE() |
数据切片/分桶 |
| 聚合类 | SUM(), AVG(), COUNT() 等 |
累计、占比 |
| 偏移类 | LAG(), LEAD() |
偏移取值 |
三、排名函数详解
三种排名对比
| 函数 | 效果 | 示例 |
|---|---|---|
ROW_NUMBER() |
连续不重复 | 1,2,3,4 |
RANK() |
有间隔 | 1,1,3,4 |
DENSE_RANK() |
无间隔 | 1,1,2,3 |
示例数据(张三、李四的成绩)
sql
姓名 科目 成绩 ROW_NUMBER RANK DENSE_RANK
---------------------------------------------------------
张三 英语 105 1 1 1
张三 语文 98 2 2 2
张三 数学 76 3 3 3
李四 语文 99 1 1 1
李四 数学 78 2 2 2
李四 英语 66 3 3 3
四、LAG / LEAD(同环比计算)
语法
sql
LAG(目标字段, 偏移量, 缺省值) OVER (PARTITION BY 分组 ORDER BY 排序)
LEAD(目标字段, 偏移量, 缺省值) OVER (PARTITION BY 分组 ORDER BY 排序)
示例数据
sql
-- 按姓名分组,按成绩排序,取上一行科目
姓名 科目 成绩 LAG(科目) 说明
---------------------------------------------
张三 数学 76 NULL -- 成绩最低,无上一行
张三 英语 105 数学 -- 上一行是数学
张三 语文 98 英语 -- 上一行是英语
李四 英语 66 NULL -- 成绩最低,无上一行
李四 数学 78 英语 -- 上一行是英语
李四 语文 99 数学 -- 上一行是数学
五、FIRST_VALUE(取首个值)
语法
sql
FIRST_VALUE(目标字段) OVER (PARTITION BY 分组 ORDER BY 排序)
示例数据
sql
-- 按姓名分组,按成绩降序,取最高分科目
姓名 科目 成绩 FIRST_VALUE(科目) 说明
---------------------------------------------
张三 英语 105 英语 -- 最高分科目
张三 语文 98 英语 -- 全部显示英语
张三 数学 76 英语 -- 全部显示英语
李四 语文 99 语文 -- 最高分科目
李四 数学 78 语文 -- 全部显示语文
李四 英语 66 语文 -- 全部显示语文
六、NTILE(数据切片)
语法
sql
NTILE(桶数) OVER (PARTITION BY 分组 ORDER BY 排序)
示例数据(2个桶,按成绩从高到低)
sql
姓名 科目 成绩 NTILE(2) 说明
----------------------------------------
张三 英语 105 1 -- 前50%
张三 语文 98 1 -- 前50%
张三 数学 76 2 -- 后50%
李四 语文 99 1 -- 前50%
李四 数学 78 1 -- 前50%
李四 英语 66 2 -- 后50%
七、聚合型开窗
三种模式对比
1. 全局窗口(无PARTITION,无ORDER BY)
sql
SUM(成绩) OVER ()
| 姓名 | 科目 | 成绩 | 全局总和 |
|---|---|---|---|
| 张三 | 语文 | 98 | 522 |
| 张三 | 数学 | 76 | 522 |
| 张三 | 英语 | 105 | 522 |
| 李四 | 语文 | 99 | 522 |
| 李四 | 数学 | 78 | 522 |
| 李四 | 英语 | 66 | 522 |
2. 分组窗口(有PARTITION,无ORDER BY)
sql
SUM(成绩) OVER (PARTITION BY 姓名)
| 姓名 | 科目 | 成绩 | 个人总和 |
|---|---|---|---|
| 张三 | 语文 | 98 | 279 |
| 张三 | 数学 | 76 | 279 |
| 张三 | 英语 | 105 | 279 |
| 李四 | 语文 | 99 | 243 |
| 李四 | 数学 | 78 | 243 |
| 李四 | 英语 | 66 | 243 |
3. 累计窗口(有PARTITION + ORDER BY)
sql
SUM(成绩) OVER (ORDER BY 成绩) -- 全局累计
SUM(成绩) OVER (PARTITION BY 姓名 ORDER BY 成绩) -- 组内累计
全局累计(按成绩升序):
| 姓名 | 科目 | 成绩 | 全局累计 | 计算过程 |
|---|---|---|---|---|
| 李四 | 英语 | 66 | 66 | 66 |
| 张三 | 数学 | 76 | 142 | 66+76 |
| 李四 | 数学 | 78 | 220 | 66+76+78 |
| 张三 | 语文 | 98 | 318 | +98 |
| 李四 | 语文 | 99 | 417 | +99 |
| 张三 | 英语 | 105 | 522 | +105 |
组内累计(按姓名分组,按成绩升序):
| 姓名 | 科目 | 成绩 | 组内累计 | 计算过程 |
|---|---|---|---|---|
| 张三 | 数学 | 76 | 76 | 76 |
| 张三 | 语文 | 98 | 174 | 76+98 |
| 张三 | 英语 | 105 | 279 | 76+98+105 |
| 李四 | 英语 | 66 | 66 | 66 |
| 李四 | 数学 | 78 | 144 | 66+78 |
| 李四 | 语文 | 99 | 243 | 66+78+99 |
八、执行顺序对比
聚合函数执行顺序
text
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
窗口函数执行顺序
text
FROM → WHERE → GROUP BY → HAVING → 窗口函数 → SELECT → ORDER BY
⚠️ 重点 :窗口函数在 GROUP BY 和 HAVING 之后执行
九、快速记忆卡
text
┌─────────────────────────────────────────────────────────────┐
│ 聚合函数 vs 窗口函数 │
├─────────────────────────────────────────────────────────────┤
│ 聚合函数:GROUP BY 压缩行数,HAVING 过滤组 │
│ 窗口函数:PARTITION BY 保留行数,OVER 开窗计算 │
├─────────────────────────────────────────────────────────────┤
│ 排名:ROW_NUMBER (连续) / RANK (跳号) / DENSE_RANK (不跳) │
│ 取值:LAG (上一行) / LEAD (下一行) / FIRST_VALUE (首行) │
│ 分片:NTILE(N) 分成 N 份 │
│ 累计:SUM/AVG OVER (ORDER BY) 实现滚动计算 │
├─────────────────────────────────────────────────────────────┤
│ 口诀: │
│ "分组聚合用GROUP,开窗计算用PARTITION" │
│ "WHERE行过滤,HAVING组过滤" │
│ "排名就在OVER里,TOP N轻松取" │
└─────────────────────────────────────────────────────────────┘