分组排序后取指定顺序数据 - 开窗/分析 函数

本文介绍了如何利用Oracle数据库的窗口函数row_number()和rank()查询每个班级的第一名学生。通过创建t_score表并插入数据,然后展示如何通过窗口函数对每个班级内部进行排序,最终筛选出每个班级得分最高的学生。同时提到了rank()函数在处理并列情况时的特点。

          和聚合函数对应着看,聚合函数是通过指定一列来统计单行数据的。开窗函数是多行。

建表(Oracle):

create table t_score(
   stuId varchar2(20),
   stuName varchar2(50),
   classId number,
   score float
);
insert into t_score(stuId,stuName,classId,score) values('111','小王',1,92);
insert into t_score(stuId,stuName,classId,score) values('123','小李',1,90);
insert into t_score(stuId,stuName,classId,score) values('134','小钱',1,92);
insert into t_score(stuId,stuName,classId,score) values('145','小顺',1,100);
insert into t_score(stuId,stuName,classId,score) values('121','小A',2,92);
insert into t_score(stuId,stuName,classId,score) values('131','小B',2,90);
insert into t_score(stuId,stuName,classId,score) values('141','小C',3,92);
insert into t_score(stuId,stuName,classId,score) values('151','小D',3,100);

分析函数:

 

 场景: 查询每个班的第一名

        步骤一:每个班的学生在自己的班级里排序

select
	        -- 表的原始字段 
					stuId, 
					stuName, 
					classId, 
					score,
					-- 多查一个排序字段
          row_number() over(partition by classId order by score desc) rn
          from t_score

         

        步骤二:找到想要的排名,以第一名为例

-- row_number() 不存在并列,一定是1.2.3....N
select *
  from (select
	        -- 表的原始字段 
					stuId, 
					stuName, 
					classId, 
					score,
					-- 多查一个排序字段
					-- row_number是一个内置函数,用来生成序号, over加在聚合函数后面表示row_number当作窗口函数(多行),而不是聚合函数(一行),partition by表示用指定字段进行分区,即依据字段值的不同来做分区表(以classid分区,则可以看作每个班级都是一个独立的分区表),因此后面的order by也是在分区表中生效,不会在全表里排序
          row_number() over(partition by classId order by score desc) rn
          from t_score)
where rn = 1; -- rn 就是序号, rn=1表示排序后的第一个,rn=2表示第二个,以此类推

        分析:首先通过窗口函数把每个班的学生按班级为单位做了分区,然后用分数做降序排列。这样就得到了一个有序号的,以班级为单位的分区表。最后只要找排名(rn=?)即可。

补充:rank()函数,统计并列情况

-- rank 存在并列的情况, 1.2.2.4....N
-- dense_rank 1.2.2.3.4...N
select stuId,
        stuName,
        classId,
        score,
-- 聚合函数rank后面加上over() 表示这是一个开窗函数,即查出来是多行(group by出来是一行),每行都有一个开窗函数的结果,partition by是指以哪个字段做分区,classid做分区,则表示1.2.3 三个班都是独立的分区表,后面的order by也是在独立分区表里面排序
        rank() over(partition by classId order by score desc) rn 
   from t_score;

 使用rank函数会把数据相同的几项的序号认为是一样的,后面的排序会跳过并列的数量。

### 开窗函数数据分析中的用法与实现 开窗函数(Window Functions)是一种强大的工具,用于在SQL查询中对数据进行复杂的分析和聚合操作,而无需改变原始查询结果的行数或顺序。这种功能特别适用于需要对大规模数据集进行复杂计算的场景[^2]。 #### 1. 开窗函数的基本语法 开窗函数的语法通常包括以下部分: ```sql <窗口函数> OVER ( [PARTITION BY <列名,...>] -- 定义窗口的分区 [ORDER BY <列名,...>] -- 定义窗口内的排序顺序 [ROWS BETWEEN <范围>] -- 定义窗口内的行范围(可选) ) ``` - `PARTITION BY`:将数据划分为多个逻辑分区,在每个分区内独立应用窗口函数- `ORDER BY`:定义窗口内数据排序规则。 - `ROWS BETWEEN`:指定窗口的行范围,例如当前行、前几行或后几行等。 #### 2. 常见的窗口函数类型 以下是几种常见的窗口函数及其用途: - **聚合窗口函数**:如 `SUM()`、`AVG()`、`COUNT()` 等,用于计算窗口内的聚合值。 - **排名窗口函数**:如 `ROW_NUMBER()`、`RANK()`、`DENSE_RANK()` 等,用于生成排名。 - **分布窗口函数**:如 `PERCENT_RANK()`、`CUME_DIST()` 等,用于计算数据的分布情况[^3]。 #### 3. 开窗函数的实现示例 以下是一些具体的实现示例: ##### 示例 1:计算累计销售额 假设有一张销售表 `sales`,包含字段 `id`、`date` 和 `amount`。可以使用 `SUM()` 窗口函数计算累计销售额: ```sql SELECT id, date, amount, SUM(amount) OVER (ORDER BY date) AS cumulative_amount FROM sales; ``` 此查询会根据日期排序,并计算每行之前的累计销售额。 ##### 示例 2:按分区计算排名 假设需要为每个部门的员工薪资排名,可以使用 `RANK()` 窗口函数: ```sql SELECT department_id, employee_id, salary, RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rank FROM employees; ``` 此查询会为每个部门的员工按照薪资从高到低排名[^2]。 ##### 示例 3:定义窗口范围 如果需要计算当前行及前后若干行的平均值,可以使用 `ROWS BETWEEN` 子句: ```sql SELECT date, value, AVG(value) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS avg_value FROM data_table; ``` 此查询会计算当前行及前后一行的平均值[^3]。 #### 4. 开窗函数的应用场景 开窗函数广泛应用于以下场景: - **时间序列分析**:计算累计值、移动平均值等。 - **排名与分组**:为数据生成排名或分配分组- **数据分配**:将数据均匀分配到多个并行进程中[^4]。 ### 注意事项 - 开窗函数不会改变原始查询结果的行数或顺序- 使用 `PARTITION BY` 时,窗口函数会在每个分区内独立计算。 - 如果未指定 `ORDER BY`,某些窗口函数(如 `ROW_NUMBER()`)可能会产生不可预测的结果[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值