Oracle之SQL分析函数

这个做统计分析的时候就用的比较多了,咱们来看一下ORACLE的分析函数,就是OVER函数,OVER PARTITION BY

OVER PARTITION BY ORDER BY,还有row_number,还有rollup,然后还有cube,还有grouping,这些语法结合去使用的一种,

主要是去做统计分析的,你可能要去做一些财务的报表啊,举个列子,这里有几条数据,然后这边有个小计,小计就是把

这几列做一下汇总,然后还有一个合计,或者是总计,把几个小计再做最后一个汇总,就是做一些表格的时候需要做的

一些东西,可能你如果不做分析函数的话,你只能用JAVA去实现了,好几个DAO,做统计,自己去查,一个一个去查,然后去

拼成一个统计的表格,那如果要用ORACLE的话,你可以去采用他的分析函数了,咱们首先看最简单的

我现在这一块,咱们先查出来,来看一下这个结果集

那这个结果集是啥意思呢,先跟着我的思路走,把EMP表的14条数据,做一下这个统计分析,做什么分析呢,

我们这里做一个连续的求和,这怎么做连续求和的呢,你会发现他有个特点是,部门10的都是8750,是这3个薪水之和,

然后部门20的都是19625,就是部门20的这些人,薪水加起来就是19625,要不然就是部门30的,这些薪水加起来就是29025,

第四列统计的都是总和,总和是什么意思呢,总和就是从头到尾所有的薪水,就是这些SAL都加起来,薪水是29025这个数,

你发现这个东西还是有增长的,它是按照部门连续求和的,你发现他有什么区别呢,这前3个字段没变,然后从第4个字段就要

连续求和了,这边sum(sal),把这个sal进行汇总,然后进行一个over,over表示一个函数,然后over里面写的是order by deptno

那首先我们不看这个,我们看这个over然后什么也不加,改成总和,这是什么意思,这个over我可以不可以把它去掉,其实就相当于去掉

他就跟sum相等,这个就是所有员工的汇总,就是29025,我们现在这里面是ORDER BY,用什么去连续求和,我根据的是deptno,

那我就把第一个部门就是8750,然后第二个部门的是,就是2975+3000+1100+800+3000,这是第二个部门的,你算一下这个结果

等于多少啊,结果是10875,就是再加上8750就等于19625,就是这个数,它是把第一个部门的和8750,然后加上第二个部门薪水的和,

加起来,等于的是19625,然后把19625再加上第三个部门的总和就等于29625,这是部门的连续求和,这是按照部门去分别求和,

如果你看不明白,你可以把它换成姓名,就可以看清楚了,比如我这里改成ORDER BY ENAME

你可以看到这个薪水是一点点增长的,然后加上1600,等于2700,2700加上2850,就等于5550,然后5500再加上2450

就等于8000,然后继续往下加,我现在按照的是名字,连续求和,就是一条记录一条记录连续的求和,最后得到的结果,

刚才我是按照部门,按照DEPNO连续求和的,而后面这个就是无所谓了,就是一个四舍五入的一个份额了,这个什么意思呢,

拿你当前的SAL,然后SUM(SAL),总数进行一个除法运算,SAL/SUM(SAL),然后结果保留5个有效数字,然后进行乘以100,

就是拿我的1100,就是和我的29025进行除,除完了之后呢,肯定是0.0几,然后我要保留5位有效数字,然后再乘以100,

然后每个人占总薪水的份额,这个应该很简单吧,刚才那个部门可能看着比较别扭,但是换成SAL就比较简单吧,

这是一个最简单的OVER的用法,OVER加上ORDER BY的用法
咱们再看第二个,可能是比较长,咱们看结果

上面就是over 加上 order by,我们这里加上一个partition,partition是什么意思呢,就是分区,分区的意思,

按照什么区域给我做什么事,那你看他有什么效果呢,你没发现当我按照分区了以后呢,部门连续求和了,咱们观察一下

这个东西,部门这个值是8750,第二个部门的是10875,第三个部门的总和是多少,是9400,那这三个值加在一起等于29025,

这个时候你会发现我是按照一个部门一个部门的去求总和的,这个就表示部门连续求和,这是怎么做的呢,注意看第二条语句,

这里多了一个PARTITION BY DEPTNO,这个就是分区,我就把它们当成一个区间,一个区域单独去计算,连续求和,按照ENAME

连续求和,去给我递增连续求和,算完了之后就完事了,第二个部门就是20部门这个,给我按照这个部门这个区域连续求和,

求出结果就可以了,同理第三个部门也是这样的,这个DEPTNO给我连续求和,这个分区就是PARTITION BY,分区的意思,下面

还有一块就是这样的,partition by deptno,就是部门的总和,你现在就是按照分区给我计算,over如果什么都不加,就是

求最终的总和,如果加上按照部门分区,你发现这是8750,这是第二个部门的总和,这是第三个部门的总和,然后这个就是占部门

的份额了,你当前第一个人的薪水,占我整个部门8750的比例,28%,57.14%,14.86%,然后再往下看就是连续求和了,刚才我写的这个,

我刚才写的是sum(sal) over (order by ename) 连续求和,直接按照这个求和也是一样的,像这种写法就是等于这个,就是一个一个

加的,其实也可以写成这种,我按照order by,按照部门,然后再按照名称,部门一次,然后再按照名称来一次, 

sum(sal) over (order by deptno,ename) 连续求和,然后就是over什么也不加,sum(sal) over () 总和,然后就是求总的

份额,partition by分区的概念,这个其实在真正的统计分析中还是非常有用的,这是ORACLE特殊的语法,这个东西应该是不难的,

其实就是把上面的简写

partition by deptno order by ename,部门分区了以后,再按照部门的名字继续给我求和,那这个结果就是DEPT_SUM,

分完区以后再按照名字给我累加,这个SUM就是求总和了

我们在加一个表EMPLOYEE,我加完EMPLOYEE这张表以后呢,我们来看看EMPLOYEE表有啥数据

数据很简单,首先是EMPID,567属于40部门,然后89属于50部门,总之就是一个部门的编号,这里有一个每个人的薪水SALARY,

大体上我们可以看到,有些人的薪水是相同的,比如第8是6500,咱们现在要做一个函数就是,ROW_NUMBER(),每个部门进行一个

大小的比较,举个例子

执行完这个SQL以后,结果是这样的,也就是排个序吗,10部门他的薪水给我排了一个序,550排在第一位,

4500排在第二位,然后20部门呢,4800排在第一位,1900排在第二位,40部门肯定是44500排在第一,然后14500排在第二,

然后6500排在第三,然后50部门的7500排在第一,6500的排在第二,把一个字段进行大小的比较,那怎么做的呢,其实跟之前

的区别就是多了一个函数,Row_Number()函数,就是Row_Number() over 然后不变,partition by deptid,先按部门分一个区,

10部门的分一个区,20部门的分一个区,40,50再给我分区,分区之后再按照薪水给我desc,给我进行一个排序,降序排序,

ORDERY BY salary desc,薪水高的在最前面,薪水低的在最下面,然后这里起一个别面叫rank,as "排名",

select employee.*, Row_Number() OVER (partition by deptid ORDER BY salary desc) as "排名" from employee;

也是一样的,这个就是关于Row_Number的用法

然后我们看另外一个小例子,可能有点复杂,建表然后插数据,这个表的数据稍微有点多,首先这个表里面有两个特殊的

关键字,EARNMONTH,月份就是09年的12月份,和10年的1月份,一共就这两个不同的数据,整个月份就两个月份,一个是09年

的12月份,一个是10年的1月份,然后区域也就两个,要么就是北平,要么就是金陵,然后SNO有相同的也有不相同的,然后就是

SNAME名称,然后就是TIMES次数,打工的次数,SINGLEINCOME就是一次多少钱,打工一次赚30块钱,那11次就是30*11就是330

块钱,就是这个意思,这就是这几个字段的一个介绍,那咱们就是用这个数据做一个分析

我现在想做group by这个分组,我代码写完以后你就知道什么意思了,直接看group by 语句,先按月份分组,这个属于分组了,

我先按月份分组,月份分组之后再按区域分组,这个结构就相当于这样的了,我们看到了这个表里面两个字段,如果我单纯的按照

月份分组,那肯定就是两条记录,要么就是09年的12月份,要么就是10年的1月份,那肯定就是两条记录,如果这么分组的话,

但是我现在按照这个分组之后,再按照区域分组,所以区域也有分组的,这就产生四条记录,0912 北平,0912金陵,1001北平,

1001金陵,就是说两次分组吗,我们看到的group by就是这样的

这个分组应该很简单吧,按照前两个字段一个简单的分组,我现在想要用rollup,做一个分组,那这个rollup是怎么概念呢,

rollup的概念是在group by 后面接rollup,这个是他的语法,就是在group by后面直接接rollup,他能做什么啊,他能够

在group by的分组上再加上earnmonth的汇总统计,在分组,再进行排序,加入我们现在这个是一个结果集,是进行group by

的一个结果集,group by两个,一个是按照时间月份,还有一个是按照AREA,还有一个是区域分组,第一次就是最简单的分组结果,

要是我如果加上rollup的话,我会在这个结果集的基础之上,我再次进行一个分组,这就是rollup的用法,先执行这个结果,

你发现这个东西就变成这样了,首先按照12月份统一给我来一个汇总,那就是12月份是1179.5+975.83=2155.33,这样的结果

就是这样的一个数,他两之和就是12月份,然后按照10年的1月份又给我汇总,他就这样再分组,然后把这两个结果相加等于最后

这个数

就是做月份的小计,这块是做这个月份的小计,然后这块就是总计,是不是可以做这样的,如果你的界面需要这种统计

分析的形式的话,那你就需要写这样的SQL语句,那现在你是利用ORACLE的分析函数,可以很清晰的做一个统计分析的

结果集,看他怎么写的呢,还是前面的是不变的,分组也不变,只是在group by 后面接了一个rollup,然后把rollup就

把earnmonth和area包裹起来,那正常来讲我们是这么来写的,正常来讲我们是group by earnmonth,area,现在我们的

写法变量,group by rollup(earnmonth,area),然后把这个月份和区域包裹起来,他肯定是按照earnmonth分组的,

如果我把两个换一下,我把它调换过来,group by rollup(area,earnmonth),就按照AREA进行再分组

不是按照时间,而是按照北平,然后北平再次分一下组,然后金陵的城市有多少,那我能不能只写一个,这肯定不行,

说不是group by的表达式,他其实也是一个group表达式的一个升级版,group by的一个升级版,group by的要求就是

分组,分组的一个数值,分组的字段,area,要么就是类似一个SUM形式的,你没法去弄一个,只能两个都得写上,你既然要查

AREA,那AREA必须是一个分组字段,那咱们继续往下看
还有一个更复杂的ORACLE的函数,这个cube函数什么意思呢,咱们先执行一下

你会发现这是另一种需求了,第一次分组之后先按月份分组,再次按照区域再次分一下组,那你发现按照月份分组,计算

的两个值,在按照区域分两个值,给我统计一下他们之间的总和,cube是有这个功能,就是两个字段分别计算,这个cube写法

也很简单,group by cube(earnmonth,area),只是rollup改成了cube,就是这两个字段需要再次去分组,那你就用这个cube,

我们刚刚学了OVER,然后PARTITION,然后还有ORDER BY,OVER函数里写了PARTITION,ORDER BY,然后group里面有group by,

也rollup,cube函数
然后就是grouping,这个函数挺简单的,你比如我们刚刚看的这个例子,rollup这个例子,我现在就是要这块小计,然后最后的

空格变成小计,这怎么办呢,有人说在JAVA里循环,然后判断AREA为空的时候再判断,然后用一个JAVA区实现一个小计,然后这块

也是用JAVA来实现一个小计,其实ORACLE在设计的时候也考虑到了这一点,所以他有了一个grouping函数,就是为了用rollup和

cube对结果集都会产生一个空值null,他汇总完以后就是一个空值,他不是北平也不是金陵,按的是月份分组的,所以这块不知道

写什么了,那你可以做什么事啊,就是这个语法吗,我可以用grouping函数,最终我执行完了就变成这样了,这可能是我们统计分析

里面经常用到的,这边就是月份小计,然后这块也是月份小计,然后这边是一个总计,就是grouping可以带一个参数,如果是本身

结果就返回0,如果是合计的结果就返回1,我这边就是case when了,这个是我们SQL通用的表达式,如果grouping(area)如果是等于

1的话,表示是合计的结果,我统计的肯定是月份,如果是不加grouping的话,那肯定是一个空值,并且grouping(area)等于0,

等于0是什么意思呢,是本身统计的一个结果,0912这块本身没有冲突,这块是0912没问题的,这块是空值,空的部分我就用月份小计

替换一下,如果是汇总的就返回1,并且grouping(earnmonth)也是汇总,两个都返回1,表示两边的值都是合计,最后一块他不知道写12月份

还是1月份了,经过汇总之后的一个空值,如果两个都是空值的话,那我就写成总计,当然我设置的是AREA这一个列,else就是原封不动的输出

AREA

这个就是grouping函数的用法,可以去把空值替换成你要的结果,能理解这个意思吗,其实不难,你不用ORACLE可能会觉得

没有多大的作用,没关系的,我觉得再过一段时间吧,ORACLE一般第二个版本是属于稳定的版本,11G第一个版本也是不稳定的,

11g的第二个版本才是稳定的,12C现在是第一个版本出了,12C如果第二个版本出了以后,集群肯定就特别特别的稳定了,

而且他那个集群是免费的,所有的互联网公司就考虑用12C吧,然后这个MYSQL肯定会被替代的,所以你可以提前当做复习了,

就是一个知识的补充,当额外学习了,总之我们第一天讲SQL的时候,这个跟整个的设计脱离的有一点点远,但是是纯ORACLE

方向的
这三个函数,一个叫RANK,一个叫dense rank,还有一个叫row_number,其实咱们可以看一下,

我把这几个直接运行了一下

主要观察Rank排名,你会发现其他的没变,还是rank() over (partition by earnmonth,area order by personincome desc) 

排名,只不过这块变成rank()了,他这里又什么功效呢,排名第一个的他们两个值都是第一,330都相等,这两人并列第一,然后

前面有两个占位了,那么第三个这个就排名第三了,本身来说这个是1,1,2,但是因为前面有个位置了,所以从第三个开始数了,

然后就是4,5

然后我们看一下dense_rank(),它是什么区别呢,他就是无论你前面有几个人,你10个人并列第一,这个就给统计打分了

然后再往下看,第三种方式就是咱们的row_number,这是啥意思呢,我们不管你这个值薪水是不是相等,我都是按照顺序

123456这么往下排的,那我也给你分成1234,这个也是在统计分析的时候,总是要前几名,以前我们做一些分析的时候,

一个数据,一个指标最高,然后给我排一个名,排一个序

区别我们这里都有,我们这里还有一个累积求和,这个应该是之前的内容了

这个东西如果有时间的话,可以让你写的,这个语句啥意思呢,我查询了这么多东西,然后主要是看第二行,sum(personincome),

最后一个数据,12月份第一个人叫大魁,11次,打工一次30块钱,一共330块钱,12月份他一共赚了330块钱,那就是薪水当月的

一个汇总,over (partition by sname order by personincome asc),那这个是啥意思呢,按照sname给我分区,sname我记得

每个人都有两个,然后1月份也有一个,我把它两个划为一个区间,然后我按照薪水分组,asc,他两就合并成一个人了,大魁就

合并成一个人了,这是330,这是0元,就是330+0,一共就是330

这里有个大凯,一开始是200,再加上350就是550了,1月份是0,然后加上330,大亮57.5+132=189.75,

就可以利用over (partition by sname order by personincome asc),反正这三个是分析函数最常用的,

组合over加上partition,加上order by,统计分析来回用这三个关键字,然后去做一些事情
还有就是做总和运算,这块有一个综合运算,我可以去求这些值里面的最高值,刚才我所有的都是用的sum,

就包括我之前的连续求和,用的group by必须用的都是用的sum,其实你不仅可以用SUM,还可以用其他的,

比如说max最大,min最小,平均值,SUM,都可以去用,这里面的最高值,我进行分组了以后,分组是按照

earnmonth,area分的组,按照月份和AREA分的组,然后就是最高值,就是201912 金陵算唯一的一个数据,

分4组,两个是唯一的一条记录,然后给我区分一下最高值,区分一下最低值,平均值,然后总额

基本上ORACLE的分析函数,基本上用法就这些,其实你做什么软件都离不开统计分析的,可能开始要实现功能,

总的做统计分析,你最终得做什么统计分析,精确的统计分析,你像我们的互联网行业要求这种精确的统计分析,

要求大概的范围,海量数据,你比如说有几亿条数据,要我做这种分析,分析两行数据是无所谓的,就看一个大概的

比值,如果你要涉及到一些真实的数据的话,有的时候他要求的是精确,要求精确的话就得你自己的去做SQL的分析,

不能依赖于hadoop,storm这些东西,你要做精确这事还得靠数据库,如果说你自己写分析呢,用JAVA些脚本,用JAVA

写代码,然后查询数据自己去写业务逻辑,写分析的规则,那这个也是挺麻烦的,ORACLE反正有这些分析函数,

SQL肯定是不支持,我个人觉得,MYSQL在过一两个版本,就是过一两年吗,现在是5.6,MYSQL如果再过几个版本,

他肯定会出分析函数,因为MYSQL就属于ORACLE下面的了,你想一下,MYSQL之前是没有sysdate的,我印象中是没有

sysdate()函数的,肯定是没有DAUL这张表,现在他都加上了,包括其实很多特性,以前都是ORACLE独有的,现在MYSQL

也都加上了,MYSQL里面有没有分区,就是create table 后面写partition,然后range,这种分区,还有hash分区,

然后list分区,MYSQL有分区吗,你们用MYSQL的数据库,有吧,我记得也是有的,也是5.几版本才有的,但是MYSQL5.0

以下是没有分区这个东西的,他不存在分区,那个时候都得用分表分库,去做,包括现在也得用分表分区去做,

是有区别的,肯定是有区别的,MYSQL正常来讲是有分区的,也就什么意思呢,MYSQL收费的肯定和免费的不一样,

版本再往前靠一靠,ORACLE这些东西可能都有,但是都有的目的就是发现你使用MYSQL和你使用ORACLE,

基本的用法都一样,MYSQL的存储过程的语法以后也得变一变,也得和ORACLE比较像,因为毕竟都差不多了,

到最后两个技术点都很像了,一个是MSYQL性能是很低的,一般情况下是不高的,你只能用集群,MYSQL就是做一个

持久化,要不然你就用ORACLE,他的性能高,而且还有集群,然后这个时候ORACLE就让你去选,你是ORACLE还是

MYSQL,到时候都用ORACLE了,今天就讲这么多东西,主要是做一个SQL语句的复习,然后不了解ORACLE的熟悉一下

ORACLE,技术点不同,但是概念都是想通的,就是一些技术,比如事务,锁啊,还有索引啊

猜你喜欢

转载自blog.csdn.net/Leon_Jinhai_Sun/article/details/90023736
今日推荐