一道SQL问题,你来试试的?
今天一位铁磁兄弟出了一道SQL题,按照如下SQL,构建测试表,
CREATE TABLE t (company VARCHAR2(10), product VARCHAR2(10), insert_time DATE);
INSERT INTO t VALUES('A', 'A1', to_date('20200109','yyyymmdd'));
INSERT INTO t VALUES('A', 'A2', to_date('20200109','yyyymmdd'));
INSERT INTO t VALUES('A', 'A1', to_date('20200222','yyyymmdd'));
INSERT INTO t VALUES('A', 'A2', to_date('20200222','yyyymmdd'));
INSERT INTO t VALUES('B', 'B1', to_date('20200225','yyyymmdd'));
INSERT INTO t VALUES('B', 'B2', to_date('20200225','yyyymmdd'));
INSERT INTO t VALUES('B', 'B1', to_date('20200501','yyyymmdd'));
INSERT INTO t VALUES('B', 'B2', to_date('20200501','yyyymmdd'));
INSERT INTO t VALUES('C', 'C1', to_date('20200201','yyyymmdd'));
INSERT INTO t VALUES('C', 'C2', to_date('20200201','yyyymmdd'));
INSERT INTO t VALUES('C', 'C1', to_date('20200510','yyyymmdd'));
INSERT INTO t VALUES('C', 'C2', to_date('20200510','yyyymmdd'));
T表数据,
SQL> select * from t;
COMPANY PRODUCT INSERT_T
---------- ---------- --------
A A1 20200109
A A2 20200109
A A1 20200222
A A2 20200222
B B1 20200225
B B2 20200225
B B1 20200501
B B2 20200501
C C1 20200201
C C2 20200201
C C1 20200510
C C2 20200510
12 rows selected.
问题:
如何通过SQL获取每个company最靠近年初的一组A1和A2的product数据?
如下所示,获取这6条数据,
我的思路是,首先肯定得按照company进行分组,其次还得按照insert_time进行排序,第三挑选排名前两位的数据。
此时,可以考虑rank()/dense_rank() over(partition by ...),其中,
partition by company,按照company进行分区。
order by insert_time,按照insert_time进行排序。
rank()/dense_rank(),分级(必须带上order by)。
逻辑如下,
按照company分区的基础之上,按照insert_time进行分级(“级别”用由小到大的数字表示(从1开始)),作为子查询,用where条件过滤级别等于1的记录。
rank()的SQL执行,
dense_rank()的SQL执行,
可以看到,都是能得到每个company最靠近年初的一组A1和A2的product数据。
解释下rank()和dense_rank(),
rank函数
用于返回结果集的分区内每行的排名,行的排名是相关行之前的排名数加一。简单来说rank函数就是对查询出来的记录进行排名,rank函数考虑到了over子句中排序字段值相同的情况,如果使用rank函数来生成序号,over子句中排序字段值相同的序号是一样的,后面字段值不相同的序号将跳过相同的排名号排下一个,就是相关行之前的排名数加一,可以理解为根据当前的记录数生成序号,后面的记录依此类推。
dense_rank函数
功能与rank函数类似,dense_rank函数在生成序号时是连续的,而rank函数生成的序号有可能不连续。dense_rank函数出现相同排名时,将不跳过相同排名号,rank值紧接上一次的rank值。在各个分组内,rank()是跳跃排序,有两个第一名时接下来就是第三名,dense_rank()是连续排序,有两个第一名时仍然跟着第二名。
执行一下,展示更形象,rank()函数,因为rank=1的是两条记录,因此排在第二位的rank=3,出现跳号,
dense_rank()函数,rank=1的有两条记录,但是第二位的rank还是等于2,
另外,SQL中用到的partition by关键字是Oracle中分析性函数的一部分,用于给结果集进行分区。他和聚合函数group by不同的地方在于他只是将原始数据进行名次排列,能够返回一个分组中的多条记录(记录数不变),而group by是对原始数据进行聚合统计,一般只有一条反映统计值的结果(每组返回一条)。
当然,这条SQL只考虑功能,未考虑性能,rank()/dense_rank()不能创建索引,如果数据量很大,这是个问题,还需要思索下,如果朋友们对这个需求有更好的解决方案,或是对性能提升有好的建议,欢迎留言,谢谢。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android 中 ThreadLocal使用示例
- Flutter基础widgets教程-Transform篇
- 借助云开发实现小程序模版消息推送(含源码)
- Android 监听软键盘状态的实例详解
- Android 中 ActivityLifecycleCallbacks的实例详解
- Android 优化Handler防止内存泄露
- Android Spinner 组件的应用实例
- Android编程实现扭曲图像的绘制功能示例
- 直播带货APP开发,圆形旋转动画
- 显存优化:纹理压缩功能介绍与使用说明
- Android编程简易实现XML解析的方法详解
- Android中SeekBar拖动条控件使用方法详解
- Android编程简单解析JSON格式数据的方法示例
- Android控件BottomSheet实现底边弹出选择列表
- Android中CheckBox复选框控件使用方法详解