SQL 窗口函数
时间:2022-07-22
本文章向大家介绍SQL 窗口函数,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
MYSQL 从 8.0.2 版本起开始支持窗口函数,那么在窗口函数没出来之前,我们要实现类似的功能该怎么做呢?
我们先用窗口函数实现一个分组排序的功能,接着再用非窗口函数的方式实现,最后对比这几种实现方式的优劣。
有两个表:emp(员工表)和 dept(表),我们要找出每个部门工资最高的前 2 名(如果出现并列的情况也要列出来)员工的个人信息。
下面是我们用到的表及数据。
DROP TABLE IF EXISTS emp;
CREATE TABLE emp ( empno INT NOT NULL, ename VARCHAR(10) DEFAULT NULL, job VARCHAR(9) DEFAULT NULL, mgr INT DEFAULT NULL, hiredate DATE DEFAULT NULL, sal DECIMAL(7,2) DEFAULT NULL, comm DECIMAL(7,2) DEFAULT NULL, deptno INT DEFAULT NULL);
DROP TABLE IF EXISTS dept;
CREATE TABLE dept ( deptno INT DEFAULT NULL, dname VARCHAR(14) DEFAULT NULL, loc VARCHAR(13) DEFAULT NULL);
INSERT INTO emp VALUES (7369,'SMITH','CLERK',7902,'1980-12-17','800.00',NULL,20);INSERT INTO emp VALUES (7499,'ALLEN','SALESMAN',7698,'1981-02-20','1600.00','300.00',30);INSERT INTO emp VALUES (7521,'WARD','SALESMAN',7698,'1981-02-22','1250.00','500.00',30);INSERT INTO emp VALUES (7566,'JONES','MANAGER',7839,'1981-04-02','2975.00',NULL,20);INSERT INTO emp VALUES (7654,'MARTIN','SALESMAN',7698,'1981-09-28','1250.00','1400.00',30);INSERT INTO emp VALUES (7698,'BLAKE','MANAGER',7839,'1981-05-01','2850.00',NULL,30);INSERT INTO emp VALUES (7782,'CLARK','MANAGER',7839,'1981-06-09','2450.00',NULL,10);INSERT INTO emp VALUES (7788,'SCOTT','ANALYST',7566,'1982-12-09','3000.00',NULL,20);INSERT INTO emp VALUES (7839,'KING','PRESIDENT',NULL,'1981-11-17','5000.00',NULL,10);INSERT INTO emp VALUES (7844,'TURNER','SALESMAN',7698,'1981-09-08','1500.00','0.00',30);INSERT INTO emp VALUES (7876,'ADAMS','CLERK',7788,'1983-01-12','1100.00',NULL,20);INSERT INTO emp VALUES (7900,'JAMES','CLERK',7698,'1981-12-03','950.00',NULL,30);INSERT INTO emp VALUES (7902,'FORD','ANALYST',7566,'1981-12-03','3000.00',NULL,20);INSERT INTO emp VALUES (7934,'MILLER','CLERK',7782,'1982-01-23','1300.00',NULL,10);
INSERT INTO dept VALUES (10,'ACCOUNTING','NEW YORK');INSERT INTO dept VALUES (20,'RESEARCH','DALLAS');INSERT INTO dept VALUES (30,'SALES','CHICAGO');INSERT INTO dept VALUES (40,'OPERATIONS','BOSTON');
我们最终要输出的结果
1. 窗口函数实现
SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno FROM (SELECT e.*, rank () over ( PARTITION BY deptno ORDER BY sal DESC ) rn FROM emp e) t WHERE rn <= 2
2. 自关联实现
SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno FROM (SELECT a.*, (SELECT COUNT(*) FROM emp b WHERE b.deptno = a.deptno AND a.sal <= b.sal) AS rn FROM emp a) e WHERE rn <= 2 ORDER BY deptno, rn
这种实现方式存在缺陷,当表中有重复数据时,结果就有可能不准确。就拿这个例子来说,如果某个部门里面有 2 人以上的工资并列第一,查询出来的结果没有该部门的数据。
3. 自定义会话变量实现
SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno FROM (SELECT e.*, @rn := IF( @deptno = deptno, (IF(@sal = sal, @rn, @rn + 1)), 1 ) + @cn AS rn, @cn := IF(@sal = sal, @cn + 1, 0), @deptno := deptno, @sal := sal FROM emp e, (SELECT @rn := 1, @cn := 0, @deptno := NULL, @sal := NULL) t ORDER BY deptno, sal DESC) t WHERE rn <= 2
使用会话变量的方式需要定义很多个变量,SQL 可读性不强,容易出错。
4. 小结
我们使用了 3 种方式实现了分组排序的功能,自关联的方式存在一点问题,数据有重复就可能导致结果出错;自定义会话变量的方式实现起来比较复杂,SQL 的可读性不强。最好的方式就是使用窗口函数,SQL 简单、高效。
- Spring/Hibernate 应用性能优化的7种方法
- 浅谈应用型机器学习作为一种搜索问题
- 自相关和偏自相关的简单介绍
- 机器学习中分类与回归的差异
- 自然语言处理指南(第1部分)
- GreenDao 兼容升级,保留旧数据的---全方面解决方案
- 基于 xorm 的服务端框架 XGoServer
- 全面总结: Golang 调用 C/C++,例子式教程
- 架构之路(六):把框架拉出来
- 第二届游戏运营技术论坛——云时代的游戏运营之道
- 如何才能准确测量 APP 的功耗?
- 可用性更高:设计优秀的MySQL和Percona XtraDB集群
- 如何使用scikit-learn在Python中生成测试数据集
- OpenStack Neutron之持续测试
- MySQL 教程
- MySQL 安装
- MySQL 管理与配置
- MySQL PHP 语法
- MySQL 连接
- MySQL 创建数据库
- MySQL 删除数据库
- MySQL 选择数据库
- MySQL 数据类型
- MySQL 创建数据表
- MySQL 删除数据表
- MySQL 插入数据
- MySQL 查询数据
- MySQL where 子句
- MySQL UPDATE 查询
- MySQL DELETE 语句
- MySQL LIKE 子句
- mysql order by
- Mysql Join的使用
- MySQL NULL 值处理
- MySQL 正则表达式
- MySQL 事务
- MySQL ALTER命令
- MySQL 索引
- MySQL 临时表
- MySQL 复制表
- 查看MySQL 元数据
- MySQL 序列 AUTO_INCREMENT
- MySQL 处理重复数据
- MySQL 及 SQL 注入
- MySQL 导出数据
- MySQL 导入数据
- MYSQL 函数大全
- MySQL Group By 实例讲解
- MySQL Max()函数实例讲解
- mysql count函数实例
- MYSQL UNION和UNION ALL实例
- MySQL IN 用法
- MySQL between and 实例讲解
- android:运行时权限工具类的封装
- Android:非Activity跳转Activity时要加FLAG?
- Java自动化测试(接口鉴权 16)
- Android:Tools命名空间原来是有大用处的
- Android:无线调试就是这么简单
- Java自动化测试(回写与断言 17)
- 一篇就够——Kotlin快速入门
- 微信大牛教你深入了解数据库索引
- SqlServer 资源消耗查询
- Android:检查通知权限并跳转到通知设置界面
- OpenShift应用发布和运维设计
- Android:依赖Module的问题汇总
- Android:加载网图时精确获取图片格式
- Android:8.0中未知来源安装权限变更
- Android:RippleDrawable 水波纹/涟漪效果