描述:习题需求,利用开窗函数取出每个年级中最小的人员的学号/年级/姓名/分数
目录
⭐️2.2 rank()、 dense_rank()、row_number()排序函数
⭐️2.6 First_value() 和Last_value()
🏆一、 开窗函数引子
描述中的需求是引子,自己又要充电了....
⭐️1.1 建表语句
/*
Navicat Premium Data TransferSource Server : 本机 SQL SERVER
Source Server Type : SQL Server
Source Server Version : 11003128
Source Host : :1433
Source Catalog : account
Source Schema : dboTarget Server Type : SQL Server
Target Server Version : 11003128
File Encoding : 65001Date: 05/01/2022 15:19:25
*/
-- ----------------------------
-- Table structure for student_2005
-- ----------------------------
IF EXISTS (SELECT * FROM sys.all_objects WHERE object_id = OBJECT_ID(N'[dbo].[student_2005]') AND type IN ('U'))
DROP TABLE [dbo].[student_2005]
GOCREATE TABLE [dbo].[student_2005] (
[num] int NOT NULL,
[txt] int NOT NULL,
[xm] char(1) COLLATE Chinese_PRC_CI_AS NOT NULL,
[fs] int NOT NULL
)
GOALTER TABLE [dbo].[student_2005] SET (LOCK_ESCALATION = TABLE)
GO
-- ----------------------------
-- Records of student_2005
-- ----------------------------
INSERT INTO [dbo].[student_2005] ([num], [txt], [xm], [fs]) VALUES (N'1', N'1', N'A', N'65')
GOINSERT INTO [dbo].[student_2005] ([num], [txt], [xm], [fs]) VALUES (N'2', N'1', N'B', N'34')
GOINSERT INTO [dbo].[student_2005] ([num], [txt], [xm], [fs]) VALUES (N'3', N'2', N'C', N'53')
GOINSERT INTO [dbo].[student_2005] ([num], [txt], [xm], [fs]) VALUES (N'4', N'2', N'D', N'12')
GO
-- ----------------------------
-- Primary Key structure for table student_2005
-- ----------------------------
ALTER TABLE [dbo].[student_2005] ADD CONSTRAINT [PK__student___DF908D6563DA5A89] PRIMARY KEY CLUSTERED ([num])
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
GO
大意了 MYSQL 没有开窗函数 所以才会一直报错
> 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(group by by txt) from student_2005' at line 1
⭐️1.2 描述
⭐️1.3 题解
select
num ,
txt,
xm,
fs
from
student_2005
where num in (select min(num) over(partition by txt) from student_2005 )
⭐️1.4 输出
⭐️1.5 思考 如果我不用开窗函数呢
题解
select num ,txt,xm,fs from student_2005 where num in (
select min(num) as num from student_2005 group by txt
)
从sql的长度上看用开窗并没有特别简洁 反倒是查询出来的结果集 重复了 单行多行这个没有太多关系 看结果来说 二者都是多行数据
好吧 那么继续往下面看吧
🏆二、开窗函数概念
⭐️2.1 什么是开窗函数
开窗函数:在开窗函数出现之前存在着很多用 SQL 语句很难解决的问题,很多都要通过复杂的相关子查询或者存储过程来完成。为了解决这些问题,在 2003 年 ISO SQL 标准加入了开窗函数,开窗函数的使用使得这些经典的难题可以被轻松的解决。目前在 MSSQLServer、Oracle、DB2 等主流数据库中都提供了对开窗函数的支持,不过非常遗憾的是 MYSQL 暂时还未对开窗函数给予支持。
所谓的开窗函数,依本人愚见,开窗函数就是 over([query_partition_clase] order_by_clause)。比如说,我采用sum求和,rank排序等等,但是我根据什么来呢?over提供一个窗口,可以根据什么什么分组,就用partition by,然后在组内根据什么什么进行内部排序,就用 order by。而下面整理的函数除over()外,都为分析函数
⭐️2.2 为要用开窗函数
开窗函数简介:与聚合函数一样,开窗函数也是对行集组进行聚合计算,但是它不像普通聚合函数那样每组只返回一个值,开窗函数可以为每组返回多个值,因为开窗函数所执行聚合计算的行集组是窗口。在 ISO SQL 规定了这样的函数为开窗函数,在 Oracle 中则被称为分析函数。
分析函数的形式
分析函数带有一个开窗函数over(),包含分析子句 。
分析子句又由下面三部分组成:
partition by :分组子句,表示分析函数的计算范围,不同的组互不相干;
ORDER BY: 排序子句,表示分组后,组内的排序方式;
ROWS/RANGE:窗口子句,是在分组(PARTITION BY)后,组内的子分组(也称窗口),此时分析函数的计算范围窗口,而不是PARTITON。窗口有两种,ROWS和RANGE;
使用形式如下:
OVER(PARTITION BY xxx PORDER BY yyy ROWS BETWEEN rowStart AND rowEnd)
思考:
下面的实战 避免开窗不支持 那就直接转战Oracle数据库吧
噢 看到这里就可以解释的通了 就是通过聚合函数查询的字段只能返回一个值
但是开窗函数的话 就可以查很多数据 两条数据甚至更多
⭐️2.3 怎么用分析、开窗函数
聚合函数 | 作用 | 分析函数 | 作用 | 详细作用 |
COUNT() | 计数 | RANK() | 给查询结果集编排名 | 结果集中如果出现两个相同的数据,那么rank会进行跳跃式的排名,比如两个第二,那么没有第三接下来就是第四 |
SUM() | 求和 | DENSE_RANK() | 但是dense_rank不会跳跃式的排名,两个第二接下来还是第三 | |
MIN() | 最小值 | ROW_NUMBER() | row_number最牛,即使两个数据相同,排名也不一样 | |
MAX() | 最大值 | RATIO_TO_REPORT() | 计算比率 | |
AVG() | 平均值 | NTILE() | 平分组 | |
LEAD() | 向上偏移 | |||
LAG() | 向下偏移 | |||
FIRST_VALUE() | 求最小值 | |||
LAST_VALUE() | 求最大值 | |||
over() | 不能单独使用要和聚合函数 排名函数后面使用 | 关键字,用于标识分析函数 |
可取值 | 说明 | 示例 |
CURRENT ROW | 当前行 | |
N PRECEDING | 前n行 | 2 preceding |
UNBOUNDED PRECEDING | 一直到第一条记录 | |
N FOLLOWING | 后N行 | 2 following |
UNBOUNDED FOLLOWING | 一直到最后一条记录 |
🏆三、分析函数实战
1 、partition by 字段名字A:子句进行分组,partition by是固定的分组语法;
2、order by 字段名字B:子句进行排序,order by 是固定的排序语法。
比如我们上面的例子就是用到了partition by classid 和 order by score这样的用法了,注意:如果联合使用指的意思是:先分组然后再排序
OVER()函数不能单独使用,必须跟在 排名函数( ROW_NUMBER、DENSE_RANK、RANK、NTILE) 或 5种聚合函数(SUM、MAX、MIN、AVG、COUNT)后边。
⭐️2.1 sum() over()求和函数
建表语句 sql server数据库
CREATE TABLE student_2008 (
name VARCHAR ( 32 ),
sale INT
);insert into student_2008(name,sale) values
('产品A',90),
('产品B',84),
('产品C',73),
('产品D',100),
('产品E',103),
('产品F',89);
求销售额的累计值
select *,sum(sale) over(order by sale) leiji from student_2008
意思就是先把sale使用over()函数排序 然后在求sale的和
⭐️2.2 rank()、 dense_rank()、row_number()排序函数
select *,RANK() over(order by sale) leiji from student_2008
select *,DENSE_RANK() over(order by sale) leiji from student_2008
select *,RANK() over(order by sale) leiji from student_2008
以上三条查询语句 都是在sale排序后使用over开启的一个窗口 在这个窗口内进行的一个排序 三条查询语句 其结果集都是一样的 如图
那一样的 我用哪个呢 有什么区别呢?
现在使用update 将我们的表数据稍稍修改一下 就可以测试 这三个排序函数到底是有什么区别 适用什么样的场景了
后续补充 .....
2022年2月24日11:05:51 先补一个 三者的区别在上面概念中详细说明了 后续有使用的可自行测试
准备数据库表
要求
sql
with tem as (
select
*
from no2004a left join no2004b using(PRODUCTID) WHERE CUSTOMID = 'C004'
) select RANK() over(ORDER BY PRICE DESC) as '排名' ,ZTIME,PRICE from tem
注意看 虽然图中的第三行记录排名是2 但是rank()排名默认 “跳跃”排名 1、2、2、4
那我换个函数排名呢 这次我换DENSE_RANK()
所以 现在 就剩下ROW_NUMBER()函数了 试一下 走起
OK 这才是我想要的排名效果 突然想起来一句话 “爱情不分对错,分先来后到” 噗
下面的函数 有空再试 感兴趣的可自行尝试
⭐️2.6 First_value() 和Last_value()
这两个属于首尾函数 在本人的其他SQL分析函数有细节拆解 这里不做过多赘述
⭐️2.7 求之前或之后的第N行
注:行比较分析函数lead和lag无window(窗口)子句。
lag(arg1,arg2,arg3) 和 lead(arg1,arg2,arg3) 可以在一次查询中取出同一字段的前n行的数据和后n行的值。这种操作可以使用对相同表的表连接来实现,不过使用lag和lead有更高的效率。
[1] arg1:参数是列名,
[2] arg2:参数是偏移的offset,
[3] arg3:参数是超出记录窗口时的默认值。
4.1 lag() over()
lag()函数向下偏移。
4.2 lead() over()
lead()函数是向上偏移。
⭐️2.8 使用多个开窗函数
在同一个SELECT语句中可以同时使用多个开窗函数,而且这些开窗函数并不会相互干扰
⭐️2.9 order by、group by
开窗函数中可以在OVER关键字后的选项中使用ORDER BY子句来指定排序规则,而且有的开窗函数还要求必须指定排序规则。使用ORDER BY子句可以对结果集按
照指定的排序规则进行排序,并且在一个指定的范围内进行聚合运算。
⭐️2.10 定位聚合计算范围
“RANGE|ROWS BETWEEN 边界规则1 AND 边界规则2”部分用来定位聚合计算范围,这个子句又被称为定位框架。
🏆四、参考文章
⭐️4.1 基础
https://www.bbsmax.com/A/ke5jk3yydr/
https://blog.csdn.net/qq_43466457/article/details/100146096
https://blog.csdn.net/jerrytomcat/article/details/82790543?spm=1001.2101.3001.6650.11&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-11.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-11.no_search_link&utm_relevant_index=18
⭐️4.2 进阶
https://www.cnblogs.com/xinaixia/p/5806386.html
http://www.cnblogs.com/lihaoyang/p/6756956.html
http://blog.itpub.net/31397003/viewspace-2140411/