MySQL:开窗函数

这篇具有很好参考价值的文章主要介绍了MySQL:开窗函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

当查询条件需要用到复杂子查询时,聚合函数操作起来非常麻烦,因此使用开窗函数能够轻松实现。

注意:在Oracle中称为分析函数。

           在MySQL中称为开窗函数,使用于MySQL8.0以上版本,sql sever、hive、Oracle等。

1 开窗函数

开窗函数:为将要被操作的行的集合定义一个窗口,它对一组值进行操作,不需要使用GROUP BY子句对数据进行分组,能够在同一行中同时返回基础行的列和聚合列。

语法:函数 + over(partition by <分组用列> order by <排序用列>)

over() 按所有行进行分组

over(partition by xxx)按xxx分组的所有行进行分组

over(partition by xxx order by aaa)按列xxx分组,按列aaa排序

over(order by aaa) 按aaa列排序

括号中的两个关键词partition by 和order by可以只出现一个。

开窗函数表示对数据集按照分组用列进行分区,并且对每个分区按照函数聚合计算,最终将计算结果按照排序用列排序后返回到该行。

无论何种能力,窗口函数都不会影响数据行数,而是将计算平摊在每一行。

1.1 开窗函数分类

名称 描述
cume_dist() 计算一组值中一个值的累积分布
dense_rank() 根据该order by子句为分区中的每一行分配一个等级。它将相同的等级分配给具有相等值的行。如果两行或更多行具有相同的排名,则排名值序列中将没有间隙
first_value() 返回相对于窗口框架第一行的指定表达式的值
lag() 返回分区中当前行之前的第N行的值。如果不存在前一行,则返回NULL
last_value() 返回相对于窗口框架中最后一行的指定表达式的值
lead() 返回分区中当前行之后的第N行的值。如果不存在后续行,则返回NULL
nth_value() 从窗口框架的第N行返回参数的值
ntile() 将每个窗口分区的行分配到指定数量的排名组中
percent_rank() 计算分区域结果集中行的百分数等级
rank() 与dense_rank()函数相似,不同之处在于当两行或更多行具有相同的等级时,等级值序列中存在间隙
row_number() 为分区中的每一行分配一个顺序整数

按照函数功能不同,MySQL支出的开窗函数分为如下几类:

  • 序号函数:row_number() / rank() / dense_rank()
  • 分布函数:percent_rank() / cume_dist()
  • 前后函数:lag() / lead()
  • 头尾函数:first_value() / last_value()
  • 其他函数 :nth_value() / nfile()

2 排序开窗函数和聚合开窗函数

2.1 排序开窗函数

  • row_number(行号)
  • rank(排名)
  • dense_rank(密集排名)
  • ntile(分组排名)

例1 先对所有数据进行排序

select s.sid,s1.sname,s1.gender,c.cname,s.num,   row_number() over 
(partition by c.cname order by num desc) as row_number排名,   
rank() over (partition by c.cname order by num desc) as rank排名,   
dense_rank() over (partition by c.cname order by num desc) as dense_rank排名,   
ntile(6) over (partition by c.cname order by num desc) as ntile排名    
from score s   join student s1 on s.student_id = s1.sid   
left join course c on s.course_id = c.cid

结果如下:

MySQL:开窗函数 row_number

根据课程进行分组,然后对每组内的成绩进行降序排序

又上图可知row_number对于同组内的相同成绩并没有做特殊处理,而仅仅是生成连续的序号。row_number常用于按照某列生成连续序号。

rank

rank函数就是对查询出来的记录进行排名。

与row_number函数不同的是,rank函数考虑到了over子句中排序字段值相同的情况,over子句中排序字段值相同的序号是一样的,后面字段值不相同的序号将跳过相同的排名号排下一个,也就是相关行之前的排名数加一,通过上面的例子我们也可以看出,rank考虑到值相同情况,并且它的排名存在跳跃性。

dense_rank

密集排名,在考虑了值相同时,排名也相同,但是序号不跳跃,紧跟上一个序号。

例如题目中体育成绩有2位同学(张三和刘三)并列第一,如果使用rank排名 ,那钢蛋就是第三名,而如果采用dense_rank 那钢蛋就是第二名,这个很容易理解吧。

ntile

ntile会先根据你的分组依据,本题中是课程名称,然后把每个组的总记录数进行按照你给的ntile()里的数字进行,这个数字就是桶数,相当于是把体育课程总共12条记录,尽量等划分成5桶,然后按照num的排序等级划分,每个桶两条记录,也就是112233445566的排序结果了,很显然,这个排序结果的数字大小只能用于桶与桶之间,而桶内部记录虽然序号相同,但是num不一定相同。

例如:统计各科成绩前三 

select * from 
(select s.sid,s1.sname,s1.gender,c.cname,s.num,dense_rank() 
over (partition by c.cname order by num desc) as dense_rank排名 from score s
join student s1 on s.student_id = s1.sid
left join course c on s.course_id = c.cid) as e
where dense_rank排名 <= 3;

2.2 聚合开窗函数

函数名如果是聚合函数,则称为聚合开窗函数

语法:聚合函数(列) over(partition by 列 order by 列)

常见的聚合函数有:sum()、count()、average()、max()、min()

计算每个学生的及格科目数

select student_id,count(sid) from  score where num>= 60 group by student_id;

MySQL:开窗函数

通过普通的聚合函数分组计算后,数据表结构发生了变化,它会根据分组进行显示,并且,如果你是根据学生ID分组,那你查询的字段应该也是学生ID,不然会影响到分组结果所对应的数值,例如现在查询条件在添加一个Sid

select sid,student_id,count(sid) from  score where num>= 60 group by student_id;

 MySQL:开窗函数

sid的数据并没有实际意义,因为数据表已经根据分组发生了变化。

执行结果

select sid,student_id,count(sid) over(PARTITION by student_id order
 by student_id) 及格数   from score where num>= 60;

 MySQL:开窗函数

 总结:开窗函数不会修改源数据表的结果,也是在表的最后一列添加想要的结果。

实例数据文章来源地址https://www.toymoban.com/news/detail-416864.html

CREATE TABLE class (
  cid int(11) NOT NULL AUTO_INCREMENT,
  caption varchar(32) NOT NULL,
  PRIMARY KEY (cid)
) ENGINE=InnoDB CHARSET=utf8;

INSERT INTO class VALUES
(1, '三年二班'), 
(2, '三年三班'), 
(3, '一年二班'), 
(4, '二年九班');

CREATE TABLE teacher(
  tid int(11) NOT NULL AUTO_INCREMENT,
  tname varchar(32) NOT NULL,
  PRIMARY KEY (tid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO teacher VALUES
(1, '张磊老师'), 
(2, '李平老师'), 
(3, '刘海燕老师'), 
(4, '朱云海老师'), 
(5, '李杰老师');

CREATE TABLE course(
  cid int(11) NOT NULL AUTO_INCREMENT,
  cname varchar(32) NOT NULL,
  teacher_id int(11) NOT NULL,
  PRIMARY KEY (cid),
  KEY fk_course_teacher (teacher_id),
  CONSTRAINT fk_course_teacher FOREIGN KEY (teacher_id) REFERENCES teacher (tid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO course VALUES
(1, '生物', 1), 
(2, '物理', 2), 
(3, '体育', 3), 
(4, '美术', 2);

CREATE TABLE student(
  sid int(11) NOT NULL AUTO_INCREMENT,
  gender char(1) NOT NULL,
  class_id int(11) NOT NULL,
  sname varchar(32) NOT NULL,
  PRIMARY KEY (sid),
  KEY fk_class (class_id),
  CONSTRAINT fk_class FOREIGN KEY (class_id) REFERENCES class (cid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO student VALUES
(1, '男', 1, '理解'), 
(2, '女', 1, '钢蛋'), 
(3, '男', 1, '张三'), 
(4, '男', 1, '张一'), 
(5, '女', 1, '张二'), 
(6, '男', 1, '张四'), 
(7, '女', 2, '铁锤'), 
(8, '男', 2, '李三'), 
(9, '男', 2, '李一'), 
(10, '女', 2, '李二'), 
(11, '男', 2, '李四'), 
(12, '女', 3, '如花'), 
(13, '男', 3, '刘三'), 
(14, '男', 3, '刘一'), 
(15, '女', 3, '刘二'), 
(16, '男', 3, '刘四');

CREATE TABLE score (
  sid int(11) NOT NULL AUTO_INCREMENT,
  student_id int(11) NOT NULL,
  course_id int(11) NOT NULL,
  num int(11) NOT NULL,
  PRIMARY KEY (sid),
  KEY fk_score_student (student_id),
  KEY fk_score_course (course_id),
  CONSTRAINT fk_score_course FOREIGN KEY (course_id) REFERENCES course (cid),
  CONSTRAINT fk_score_student FOREIGN KEY (student_id) REFERENCES student(sid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO score VALUES
(1, 1, 1, 10),
(2, 1, 2, 9),
(5, 1, 4, 66),
(6, 2, 1, 8),
(8, 2, 3, 68),
(9, 2, 4, 99),
(10, 3, 1, 77),
(11, 3, 2, 66),
(12, 3, 3, 87),
(13, 3, 4, 99),
(14, 4, 1, 79),
(15, 4, 2, 11),
(16, 4, 3, 67),
(17, 4, 4, 100),
(18, 5, 1, 79),
(19, 5, 2, 11),
(20, 5, 3, 67),
(21, 5, 4, 100),
(22, 6, 1, 9),
(23, 6, 2, 100),
(24, 6, 3, 67),
(25, 6, 4, 100),
(26, 7, 1, 9),
(27, 7, 2, 100),
(28, 7, 3, 67),
(29, 7, 4, 88),
(30, 8, 1, 9),
(31, 8, 2, 100),
(32, 8, 3, 67),
(33, 8, 4, 88),
(34, 9, 1, 91),
(35, 9, 2, 88),
(36, 9, 3, 67),
(37, 9, 4, 22),
(38, 10, 1, 90),
(39, 10, 2, 77),
(40, 10, 3, 43),
(41, 10, 4, 87),
(42, 11, 1, 90),
(43, 11, 2, 77),
(44, 11, 3, 43),
(45, 11, 4, 87),
(46, 12, 1, 90),
(47, 12, 2, 77),
(48, 12, 3, 43),
(49, 12, 4, 87),
(52, 13, 3, 87);

到了这里,关于MySQL:开窗函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ElasticSearch多条件复杂查询实现

    前面实现方式和但条件一致 查询代码区别如下 注释里面标注了或者和and那两行的区别 网站链接 elasticsearch(ES)在SpringBoot中的复杂查询(多条件分页查询以及聚合查询)_尺规作图的博客-CSDN博客_springboot 整合es多条件

    2024年02月04日
    浏览(47)
  • MySQL:开窗函数

    当查询条件需要用到复杂子查询时,聚合函数操作起来非常麻烦,因此使用开窗函数能够轻松实现。 注意:在Oracle中称为分析函数。            在MySQL中称为开窗函数,使用于MySQL8.0以上版本,sql sever、hive、Oracle等。 开窗函数:为将要被操作的行的集合定义一个窗口,它对

    2023年04月18日
    浏览(28)
  • 【SQL】MySQL中的窗口函数(开窗函数)

    窗口函数是 MYSQL8.0 新增的 聚合函数: 多行变一行,常见的sum,count,max,min 窗口函数: 行数不变,常见的row_number,rank 语法格式: 窗口函数(表达式) over (partition by … order by … frame_clause) partition by是分区,类似于group by,如去掉相当于对所有数据进行计算 order by排序 frame_c

    2024年02月07日
    浏览(47)
  • ElasticSearch第十四讲 ES有条件复杂查询

    模糊匹配 模糊匹配主要是针对文本类型的字段,文本类型的字段会对内容进行分词,对查询时,也会对搜索条件进行分词,然后通过倒排索引查找到匹配的数据,模糊匹配主要通过match等参数来实现 match : 通过match模糊匹配条件内容 prefix : 前缀匹配 regexp : 通过正则表达

    2024年02月03日
    浏览(45)
  • MySQL8.0数据库开窗函数

          数据库开窗函数是一种在SQL中使用的函数,它可以用来对结果集中的数据进行分组和排序,以便更好地分析和处理数据。开窗函数与聚合函数不同,它不会将多行数据聚合成一行,而是保留每一行数据,并对其进行分组和排序。 常见的开窗函数包括ROW_NUMBER()、RANK()、

    2024年02月08日
    浏览(63)
  • 【Mysql系列】LAG与LEAD开窗函数

    💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老 导航 檀越剑指大厂系列:全面总

    2024年02月05日
    浏览(48)
  • QueryWrapper构建复杂的SQL-循环添加条件、联表查询

    QueryWrapper是MyBatis-Plus提供的一个查询构建器,用于构建复杂的SQL查询语句。QueryWrapper可以用于添加条件、排序、分页等操作。 循环添加条件 在QueryWrapper中,可以使用andWhere和orWhere方法来添加多个条件,从而实现循环添加条件。 下面是一个示例代码,演示如何使用QueryWrapper循

    2024年02月16日
    浏览(45)
  • MySQL---控制流函数、窗口函数(序号函数、开窗聚合函数、分布函数、前后函数、头尾函数、其他函数)

    格式 解释 案例 IF(expr,v1,v2) 如果表达式 expr 成立,返回结果 v1 ;否则,返回结果 v2 。 SELECT IF(1 0,\\\' 正确 \\\',\\\' 错误 \\\')    - 正确 IFNULL(v1,v2) 如果 v1 的值不为 NULL ,则返回 v1 ,否则返回 v2 。 SELECT IFNULL(null,\\\'Hello Word\\\') -Hello Word ISNULL(expression) 判断表达式是否为 NULL SELECT ISNULL(NUL

    2024年02月04日
    浏览(46)
  • ES简单教程(四)使用ElasticsearchRestTemplate多条件分页查询(复杂版)

    TIPS :本文实现类似数据库后台管理系统的多条件分页查询。

    2024年02月11日
    浏览(45)
  • SQL-条件查询与聚合函数的使用

     🎉欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克🍹 ✨博客主页: 小小恶斯法克的博客 🎈该系列文章专栏: 重拾MySQL 🍹文章作者技术和水平很有限,如果文中出现错误,希望大家能指正🙏 📜 感谢大家的关注! ❤️ 目录 DQL-条件查询 1.语法

    2024年01月23日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包