【SQL实用技巧】-- 窗口函数的使用

窗口函数问题

数据准备

用来学习窗口函数

create table student (
    class_id int comment '班级编号',
    name varchar(10) comment '学生姓名',
    score int comment '考试分数'
);
insert into student values
( 1,'张三',60),
( 1,'李四',70),
( 1,'王五',80),
( 1,'赵六',90),
( 2,'小明',80),
( 2,'小强',90);
select * from student;
窗口函数语法:
窗口函数名(参数) over(partition by 分组字段 order by 排序字段 rows between 起点 and 终点) as 新字段名
聚合类窗口函数

问题1:让每个学生知道各自班级内的总分是是多少:

select *,
       -- 班级内总分是多少
       -- 写法1
       sum(score) over(partition by class_id order by score rows between unbounded preceding and unbounded following) as sum1,
       -- 简化写法2
       sum(score) over(partition by class_id) as sum2
 from student;

rows between unbounded preceding and unbounded following意思是对上面排序后的数据,从 unbounded preceding 直译为向前最远边界的那行,也就是张三 60 分那行,到 unbounded following 直译为向后最远边界的那行,也就是赵六 90 分那行,形成一个子窗口

问题2:让每个学生知道,班级内小于等你与自己的同学的总分是多少:

select *,
       -- 班级内分数小于等于自己的同学的总分是多少
       -- 写法1
       sum(score) over(partition by class_id order by score rows between unbounded preceding and current row) as sum3,
       -- 简化写法2
       sum(score) over(partition by class_id order by score) as sum4
 from student;

和上一个问题相比是把 unbounded following换为了 current row

rows between unbounded preceding and current row,意思是对上面排序后的数据,从 unbounded preceding (向前最远边界的那行),也就是张三 60 分那行,到 current row 直译为当前行,也就是李四 70 分本行,形成一个子窗口,也就是张三 60、李四 70 这 2 行

注意:需要记住省略的 rows between unbounded preceding and current row,一般用在累加场景

问题3:如何让每个学生知道,比自己高和低1名的同学及自己三人的总分是多少:

select *,
       -- 班级内每个学生,比他分数高1名的同学、低1名的同学,和自己3人的总分是多少
       sum(score) over(partition by class_id order by score rows between 1 preceding and 1 following) as sum5
 from student;

聚合类的 count、avg、max、min使用方式与sum类似。

排序类窗口函数

排序类窗口函数有3个,分别是 row_number, rank,dense_rank

三者的不同点: row_number :排序后给连续的序号,不考虑并列名次。 rank :排序后,如果有并列名次,则序号一样,且会跳过下一序号,使序号不连续。 dense_rank :排序后,如果有并列名次,则序号一样,且不会跳过下一序号,序号是连续的

在上个案例基础上补充数据:

insert into student values
( 1,'小乔',70);
select * from student order by class_id,score;

问题:看每个班级内,按考试分数排序情况

-- 排序类的窗口函数
select *,
       -- 用row_number连续排序
       row_number() over(partition by class_id order by score) rn,
       -- 用rank并列排序,考虑并列且序号不连续
       rank() over(partition by class_id order by score) rk,
       -- 用dense_rank并列排序,考虑并列且序号连续
       dense_rank() over(partition by class_id order by score) drk
from student;

排序窗口函数使用时,不用写rows between 起始 and 结束

偏移类的,跨行的窗口函数

一共有2个,分别是 laglead 函数,分别是向前,向后。

函数语法:
LAG(expression,offset,default_value) OVER (
    PARTITION BY expr,...
    ORDER BY expr [ASC|DESC],...
)

都有三个参数,第一个参数是列名(需要偏移的字段),第二个参数是偏移量(offeset),第三个参数是超出记录窗口时的默认值(默认为null,可设置为0)

问题:如何让每个学生知道,在班级内,考试分数比自己低1名的同学的分数,以及比自己高一名的同学的分数,找不到就显示空。

避免上一个案例的干扰,这里先删除小乔同学。

delete from student where name='小乔';
select * from student ;
实现:
select *,
       -- 获取比自己低2个名次的学生的分数,若找不到则显示0
       lag(score,2,0) over(partition by class_id order by score) lag2,
       -- 获取比自己高2个名次的学生的分数,若找不到则显示0
       lead(score,2,0) over(partition by class_id order by score) lead2
from student;
其它窗口函数
获取第N行的值

这类窗口函数有 3 个,分别是 first_valuelast_valuenth_value

first_value() :返回窗口中第 1 个值。

last_value() :返回窗口中最后的值。

nth_value(expr,n) :返回窗口中第 N 个值。

问题:

如何让每个学生都知道,本班级内,考试分数最低的分数,以及最高的分数

实现:
select *,
       -- 获取本班级内,考试分数最低的分数
       first_value(score) over(partition by class_id order by score) first,
       -- 获取本班级内,考试分数最高的分数 ,的正确用法
       last_value(score) over(partition by class_id order by score rows between unbounded preceding and unbounded following) last
from student;
分布函数

目前是简单了解

percent_rank()

  • 用途:和之前的 RANK() 函数相关,每行按照如下公式进行计算:
    • (rank - 1) / (rows - 1)
    • 其中,rank 为 RANK() 函数产生的序号,rows 为当前窗口的记录总行数。
  • 应用场景:用的比较少,了解就好。

cume_dist()

  • 用途:分组内小于等于当前 rank 值的行数/分组内总行数,这个函数比 percen_rank 使用场景更多。
使用
select *,
    rank() over w as rank_num,
    percent_rank() over w as percent,
    cume_dist() over w as cume
from student window w as (
        partition by class_id
        order by score
    );

省略了 rows between unbounded preceding and current row 。这会造成什么呢?比如以李四行做为分析对象,子窗口只圈定了从张三到自己之间的行,窗口内末尾就是李四自己,返回了 70,而不是 90。若要想返回 90,则必须将 current row 替换成 unbounded following

select *,
       -- 获取本班级内,考试分数最高的分数 ,之错误用法
       last_value(score) over(partition by class_id order by score ) last1,
       -- 因为上句等价于:
       last_value(score) over(partition by class_id order by score rows between unbounded preceding and current row) last2
from student;

思考在班级内按分数排序之后,如何获取截至目前,排名第二和第三的分数。

select *,
    nth_value(score,2) over w second_score,
    nth_value(score,3) over w third_score
from student window w as (
        partition by class_id
        order by score
    );
分组 ntile

NTILE(n) 函数用于将一组分区中的有序数据再尽量平均划分为 n 个小组 。

select *,
       ntile(2) over(partition by class_id order by score) subgroup
from student;
  • 37
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
jsp编程的一些小技巧总结,绝对实用。包括JSP编程中常用的js技术。 1.JSP编程中常用的js技术 2. 在下拉列表框里选择一个值后跳出新窗口? 3. 在JSP中启动execl? 4. 两级下拉列表框联动菜单? 5. java中如何把一个目录下的文件移到另一个指定的目录? 6. 制作表格线? 7. jsp如判别一个字符在A到Z之间? 8. 得到一浮点数小数点后4位,如何写以函数截取为两位 9. 整型转字符? 10. 显示数据库的记录,点击哪个标题栏,就按照哪个标题排序 11. 制作两个按钮 12. 用什么sql语句将数据库中的一条记录,复制为两条? 13. 有兩個按鈕A,B,其中A按下去,A就不可以再按,另外B按下去,A可以再按..請問如何用javascript控制.? 14. jsp中的数据库的连接方式 15. 在jsp中,怎么实现按回车就可提交表单? 16. 在JSP中如何传递数组? 17. 按地址取图片? 18. JSP中如何上传图片到数据库字段? 19. 页面自动刷新? 20. 表单自动提交? 21. 从JSP传数据的到JAVABEAN里? 22. weblogic 数据池连接? 数据源 JNDI名字 mysource 23. 三级下拉列表框联动菜单? 24. 在JSP中如何调用浏览器中的"另存为"功能? 25. 网页全屏显示 26. 求两个日期相隔了多少天:输入时间格式为(yyyy-mm-dd) 27. 上传文件对话框 28. 分页测试 29. 下载文件 30. 简单汉字判断 31. 将JSP的变量或者bean传递给JAVASCRIPT使用? 32. 把一种格式(如yyyy-mm-dd)的日期变量转换成另外一种格式(如dd-mm-yyyy)的日期变量! 33. 实现在页面上添加一行输入对话框 34. 制作验证码图片? 35. 图片缩小放大功能 36. 点击输入框弹出日期选择? 37. 在图片上传前查看自己要上传的图片? 38. 在图片排列的页面上选中一个图片,然后把它删掉? 39. 显示某目录下的所有文件 40. 把复选框中选中的值直接显示在输入文本框中? 41. 选择路径下的文件直接显示文件内容? 42. 制作进度条? 43. 对较长字符省略显示? 44. 制作日历? 45. 点击文本弹出一个选择框,选中值后返回并显示 46. 关闭框架页面回到没框架的页面? 47. 选中多条记录一次性删除? 48. 自动获取页面文件名? 49. 在JSP中调用ActiveX控件? 50. 使用SmartUpload实现文件上传? 51. 使用iReport和Jasperreport开发报表? 52. 使用iText生成PDF? 53. 制作图片水印? 54. 在页面中屏蔽键盘功能键? 55. 禁止用户复制网页内容? 56. 实现不在地址拦中显示当前URL? 57. 获取用户的真实IP地址? 58. 获取用户浏览器信息? 59. 获取当前绝对路径? 60. 将HTML文件转换成XML文件? 61. 结合XML和XSL输出HTML页面? 62. 制作动态树型菜单制作? 63. 制作类似QQ的短消息提示? 64. 用jfreechat制作拄、饼、曲线图型? 65. 文本框怎么只容许输入数字? 66. 打开Word和Execl文件? 67. 生成Word 和 Excel文档? 68. JSP如何读取Word内容? 69. 浏览服务器目录/文件? 70. jsp直接弹出下载框下载文件? 71. 配置数据连接池和数据源(Tomcat)? 72. 点击图1变为图2? 73. JSP中显示图片的方法之一? 74. int转为Integer的方法? 75. 请求jsp页面禁止缓存方法? 76. select选中其中的值自动到一个文本框? 77. JSP连接数据库? 78. JSP两级下拉列表框联动(数据库)? 79. JSP字符编码问题及转换大全? 80. 使用过滤器设置请求编码? 81. JSP或Servlet调用DLL? 82. 在JSP中包含Applet(时钟)? 83. 在Applet中显示一个html页面? 84. 使session强制失效85. iFreme编辑框使用? 86. Applet与Servlet的通讯? 87. JSP表格直接导入EXCEL? 88. 访问类路径上的资源? 89. 操作文件目录? 90. 获取文件的属性? 91.如何开发并部署一个servlet 92.如何取得配置文件中的servlet的参数 93.使servlet成为线程安全的 94.访问标准的CGI变量 95. servlet之间及与jsp间的通讯 96.获取当前绝对路径 97.在servlet中操作cookie 98.使用servlet生成JPE

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值