窗口函数的使用

语法

‹窗口函数› over
(partition by ‹用于分组的列名›
order by ‹用于排序的列名›)

‹窗口函数›的位置,可以放以下两种函数:

  1. 专用窗口函数,比如rank, dense_rank, row_number等

  2. 聚合函数,如sum. avg, count, max, min等

专用窗口函数

表数据

RowID DeptID PaidYear PaidAmount
1 10001 2022 20000
2 10002 2022 15000
3 20001 2022 10000
4 20002 2022 300000
5 20003 2022 10000
6 30001 2022 8000
7 10001 2021 5000
8 10002 2021 8000
9 20001 2021 10000
10 20002 2021 250000
11 20003 2021 10000
12 30001 2021 20000
建表语句
CREATE TABLE [DeptPaid](
	[RowID] [bigint] IDENTITY(1,1) NOT NULL,
	[DeptID] [bigint] NOT NULL,
	[PaidYear] [nchar](4) NULL,
	[PaidAmount] [numeric](18, 2) NULL
) ON [PRIMARY]

INSERT [DeptPaid] ([RowID], [DeptID], [PaidYear], [PaidAmount]) VALUES (1, 10001, N'2022', CAST(20000.00 AS Numeric(18, 2)))
INSERT [DeptPaid] ([RowID], [DeptID], [PaidYear], [PaidAmount]) VALUES (2, 10002, N'2022', CAST(15000.00 AS Numeric(18, 2)))
INSERT [DeptPaid] ([RowID], [DeptID], [PaidYear], [PaidAmount]) VALUES (3, 20001, N'2022', CAST(10000.00 AS Numeric(18, 2)))
INSERT [DeptPaid] ([RowID], [DeptID], [PaidYear], [PaidAmount]) VALUES (4, 20002, N'2022', CAST(300000.00 AS Numeric(18, 2)))
INSERT [DeptPaid] ([RowID], [DeptID], [PaidYear], [PaidAmount]) VALUES (5, 20003, N'2022', CAST(10000.00 AS Numeric(18, 2)))
INSERT [DeptPaid] ([RowID], [DeptID], [PaidYear], [PaidAmount]) VALUES (6, 30001, N'2022', CAST(8000.00 AS Numeric(18, 2)))
INSERT [DeptPaid] ([RowID], [DeptID], [PaidYear], [PaidAmount]) VALUES (7, 10001, N'2021', CAST(5000.00 AS Numeric(18, 2)))
INSERT [DeptPaid] ([RowID], [DeptID], [PaidYear], [PaidAmount]) VALUES (8, 10002, N'2021', CAST(8000.00 AS Numeric(18, 2)))
INSERT [DeptPaid] ([RowID], [DeptID], [PaidYear], [PaidAmount]) VALUES (9, 20001, N'2021', CAST(10000.00 AS Numeric(18, 2)))
INSERT [DeptPaid] ([RowID], [DeptID], [PaidYear], [PaidAmount]) VALUES (10, 20002, N'2021', CAST(250000.00 AS Numeric(18, 2)))
INSERT [DeptPaid] ([RowID], [DeptID], [PaidYear], [PaidAmount]) VALUES (11, 20003, N'2021', CAST(10000.00 AS Numeric(18, 2)))
INSERT [DeptPaid] ([RowID], [DeptID], [PaidYear], [PaidAmount]) VALUES (12, 30001, N'2021', CAST(20000.00 AS Numeric(18, 2)))

select *,
rank() over (order by PaidAmount desc) as ranking,
dense_rank() over (order by PaidAmount desc) as dese_rank,
row_number() over (order by PaidAmount desc) as row_num
from DeptPaid where PaidYear='2022'
RowID DeptID PaidYear PaidAmount ranking dese_rank row_num
4 20002 2022 300000 1 1 1
1 10001 2022 20000 2 2 2
2 10002 2022 15000 3 3 3
3 20001 2022 10000 4 4 4
5 20003 2022 10000 4 4 5
6 30001 2022 8000 6 5 6

聚合函数

sqlserver2012以上版本支持

select *,
sum(成绩) over (order by 学号) as current_sum,
avg(成绩) over (order by 学号) as current_avg,
count(成绩) over (order by 学号) as current_count,
max(成绩) over (order by 学号) as current_max,
min(成绩) over (order by 学号) as current_min
from 班级表;

image

窗口函数的移动平均

sqlserver2012以上版本支持

select *,
avg(成绩) over
(order by 学号 rows 2 preceding) as current_avg
from 班级表;

image

rows和preceding这两个关键字,是“之前~行”的意思,上面的句子中,是之前2行(总计最多3行)。也就是得到的结果是自身记录及前2行的平均。想要计算当前行与前n行(共n+1行)的平均时,只要调整rows…preceding中间的数字即可。

适用于:在公司业绩名单排名中,可以通过移动平均,直观地查看到与相邻名次业绩的平均、求和等统计数据。

使用场景

  1. 经典top N问题
    找出每个部门排名前N的员工进行奖励

    # topN问题 sql模板
    select * from
    (select *,
    row_number() over
    (partition by 要分组的列名
    order by 要排序的列名 desc) as ranking  from 表名) as a
    where ranking ‹= N;
    
  2. 经典排名问题
    业务需求“在每组内排名”,比如:每个部门按业绩来排名

  3. 在每个组里比较的问题
    比如查找每个组里大于平均值的数据

posted @ 2023-01-19 09:45  KeepChasing  阅读(66)  评论(0编辑  收藏  举报