第5章
CHAPTER 5


SQL数字的查询与处理












5.1MySQL 8.0的数字

每种语言与数据库都含有针对处理数字的数据类型。

在Java中含有short、int、long、float、double等数据类型,用于处理与数字有关的逻辑与业务。

在MySQL中含有int、bigint、float、double等数据类型,用于处理与数字有关的逻辑与业务。

5.1.1MySQL 8.0中的数字类型

MySQL 8.0中支持的数字类型如表51所示。


表51MySQL 8.0中支持的数字类型



数 字 类 型长度释义


tinyint[(m)]有符号整数: -128~127

无符号整数: 0~255需要1字节存储空间。m是可选的显示宽度,不影响值的范围
smallint[(m)]有符号整数: -32768~32767

无符号整数: 0~65535需要2字节存储空间。m是可选的显示宽度,不影响值的范围
mediumint[(m)]有符号整数: -8388608~8388607

无符号整数: 0~16777215需要3字节存储空间。m是可选的显示宽度,不影响值的范围
int[(m)]有符号整数: -2147483648~2147483647

无符号整数: 0~4294967295需要4字节存储空间。m是可选的显示宽度,不影响值的范围
bigint[(m)]有符号整数: -9223372036854775808~9223372036854775807

无符号整数: 0~18446744073709551615需要8字节存储空间。m是可选的显示宽度,不影响值的范围,但是要注意对较大的值进行代数运算可能会出现错误
float[(m,d)]精确到小数点后7位左右单精度的浮点值,m为最大位数,并可包含小数点后的d位小数。注意许多十进制的数字遇浮点类型会丧失精度,若需要确切的值,则应更改为decimal类型
double[(m,d)]精确到小数点后15位左右m为最大位数(最大位数包含整数+小数),并可包含小数点后的d位小数。注意许多十进制的数字遇浮点类型会丧失精度,若需要确切的值,则应更改为decimal类型
double precision[(m,d)]double的别名与double一致
real[(m,d)]默认为double别名若设置了real_as_float,则为float别名
decimal[(m[,d])]m(精确度): 高达65位

d(小数): 0~30位非浮点的确切十进制类型,其中m为最大位数,并可包含小数点后的d位小数。如有必要,则类型将四舍五入
bit[(m)]m默认值为1,范围为1~64位字段类型,其中m用于指定位数。若输入值位数小于m,则对齐到最后一位。

若要单独命名每位,则可参考set
serial范围: 0~18446744073709551615serial是bigint unsigned not null auto_increment unique的别名。



unsigned 指无序号

not null 指不为空

auto_increment指自增

unique 指唯一约束
boolbool是tinyint(1)的别名
booleanboolean是tinyint(1)的别名
dec[(m[,d])]dec是decimal的别名,除了dec之外decimal的别名还有fixed和numeric


5.1.2tinyint类型、bool类型、boolean类型


tinyint类型是MySQL中最小的数字类型,仅需1字节进行存储,可存储有符号整数-128~127,或无符号整数0~255。

创建表时将字段设置为tinyint类型的SQL语句如下: 


create table test_tinyint(t1 tinyint(1));


向test_tinyint表中添加测试数据,SQL语句如下: 


insert into test_tinyint values(10);

insert into test_tinyint values(127);

insert into test_tinyint values(-128);


查询语句如下: 


select * from test_tinyint;


运行后,结果集如图51所示。

在MySQL中,bool与boolean本质上就是tinyint字段,可创建字段为bool类型和boolean类型的SQL语句如下: 


create table test_bool(t1 bool,t2 boolean);


向test_bool表中添加测试数据,SQL语句如下: 


insert into test_bool values(0,0);

insert into test_bool values(1,1);

insert into test_bool values(true,true);

insert into test_bool values(false,false);


查询语句如下: 


select * from test_bool;


运行后,结果集如图52所示。




图51查询tinyint字段结果




图52查看boolean字段结果




5.1.3无符号整数类型

在MySQL 8.0中创建数字类型在默认情况下是“含有符号的数字类型”,例如创建含有int数字类型的测试表,SQL语句如下: 


create table test_int1 (t1 int);


增加测试表之后,可插入列值2147483648,SQL示例语句与报错如下: 


insert into test_int1 value(2147483648);

--报错Out of range value for column 't1' at row 1


报错中说明已经超过t1列值的承受能力了。MySQL 8.0中提供了有符号整数和无符号整数两种写法,默认创建的数字类型皆为有符号整数,创建无符号整数时需要增加关键字unsigned,创建无符号整数的SQL语句如下: 


--创建无符号整数类型的表test_int2

create table test_int2 (t1 int unsigned);

--添加数据

insert into test_int2 value(2147483648);


5.1.4数字类型的精度

创建double类型,将精度设置为2的SQL语句如下: 


-- 创建float和decimal类型表

create table test_float(t1 float(10,2), t2 decimal(10,2));


其中float的最大位数为10,代表着整数最多为8位,小数为2位。添加数据的示例SQL语句如下: 


insert into test_float values(12345678.21, 12345678.12);


若输入以下SQL语句,MySQL则会报错。


insert into test_float values(1234567890, 1234567890);

--报错为Out of range value for column 't1' at row 1




图53查看浮点字段结果

在没有输入任何小数时会默认将小数填充为0。添加没有任何小数的SQL语句如下: 


insert into test_float values(12345678, 12345678);


通过SQL语句查询test_float的结果集如图53所示。

5.2数字常用函数与运算符

MySQL中一共含有37种不同的数字常用函数(Numeric Functions)与运算符,可通过如下SQL语句在MySQL数据库中查询数字常用函数。


//代码位置: 全书代码/5.2 数字常用函数与运算符.sql



select

*

from

mysql.help_topic ht

where

ht.help_category_id = (

select






hc.help_category_id

from

mysql.help_category hc

where

hc.name = 'Numeric Functions'#数字处理相关函数

);


在实际工作中对于MySQL数字处理大多数基于加减乘除和百分数,其余函数使用较少,例如正弦函数sin()、余弦函数cos()、正弧线函数asin()、正切函数atan()、余切函数cot(),此处仅列举部分MySQL处理数字的相关常用函数。

5.2.1div()函数

div()将对数字进行整数除法,为数字处理类函数。从除法结果中丢弃任何小数部分,SQL语句如下: 


select 5 div 2, -5 div 2, 5 div -2, -5 div -2;

--返回结果2, -2, -2, 2


5.2.2abs()函数

abs()函数将返回绝对值,为数字处理类函数。若输入内容为null关键字,则会返回null,SQL语句如下: 


select abs(2);#返回 2

select abs(-32);#返回 32


5.2.3ceiling()函数

ceiling(X)函数将返回不小于X的最小整数值,为数字处理类函数,SQL语句如下: 


select ceiling(1.23); #返回 2

select ceiling(-1.23);#返回 -1


5.2.4floor()函数

floor(X)函数将返回不大于X的最大整数值,为数字处理类函数,SQL语句如下: 


select floor(1.23), floor(-1.23);#返回 1, -2


5.2.5pow()函数和power()函数

pow(X,Y)函数将返回X的Y次幂,为数字处理类函数,SQL语句如下: 


select pow(2,2);#返回 4

select pow(2,-2); #返回 0.25


power(X,Y)函数是pow(X,Y)函数的别名,效果完全相同。

5.2.6rand()函数

rand()返回范围为0≤v<1.0的随机浮点值,v为返回的值,为数字处理类函数。如需返回整数,则需使用以下的公式: 


FLOOR(i + RAND()* (j - i))


例如要获得随机整数在范围7≤R<12内,SQL语句如下: 


select floor(7 + (rand()* 5));


5.2.7truncate()函数

truncate(X,D)函数返回数字X,截断为D位小数。为数字处理类函数。若D为0,则结果并没有小数点或小数部分。D可以是负数。使值X的小数点左边的D位变为0,SQL语句如下: 


//代码位置: 全书代码/5.2.7 truncate()函数.sql



select truncate(1.223,1);#返回 1.2

select truncate(1.999,1);#返回 1.9

select truncate(1.999,0);#返回 1

select truncate(-1.999,1);#返回 -1.9

select truncate(122,-2);#返回 100

select truncate(10.28*100,0);#返回 1028


5.3聚合函数

MySQL还经常运用聚合函数和修饰符(Aggregate Functions and Modifiers)类型的函数。在MySQL数据库中查询聚合函数和修饰符的SQL语句如下。


//5.3 聚合函数.sql



select

*

from

mysql.help_topic ht

where

ht.help_category_id = (

select

hc.help_category_id






from

mysql.help_category hc

where

hc.name = 'Aggregate Functions and Modifiers' 

#聚合函数和修饰符

);


聚合函数和修饰符是MySQL中比较特殊的函数类型,聚合函数的特点是可以根据group by关键字进行分组聚合。

group by分组必须跟随在聚合函数之后,但聚合函数的使用不一定非得含有group by分组。

5.3.1count(distinct)函数

count(distinct)函数可进行去重统计总行数,SQL语句如下: 


select count(distinct sal) from emp;#返回11

select count(sal) from emp;#返回14


5.3.2查询每个部门的平均薪资

例如公司表(emp表)中含有薪资列(sal列),但是当直接使用avg()函数对emp表的sal列进行聚合计算平均值时会算出所有人员的薪资平均值。若想按照公司的不同部门进行不同平均值计算,则需使用group by 对emp表的部门进行分组。

因为聚合函数将会运行在group by关键字之后,所以可以进行分组聚合,SQL语句如下: 


//5.3 聚合函数.sql



---查询每个部门的平均薪资

select

deptno,

avg(sal)

from

emp

group by

deptno;


聚合函数中包括的返回列最大值max()函数、返回列最小值min()函数、返回列平均值avg()函数、返回列总和sum()函数、返回列平均值avg()函数、返回列总行数count()函数、返回列总行数且去重count(distinct)函数等。

聚合函数只需在函数中输入列名便可以使用,针对列名进行聚合计算。

所有聚合函数皆可使用group by进行分组。

5.3.3查询每个部门的薪资最高与最低的人(携带提成)

在emp表中含有comm字段代表提成,正常情况下只需使用sal+comm便可以获得携带提成的薪资,但此张表含有问题,即comm字段可能为null。若使用了1+null的方式,则会返回null,SQL语句如下: 


select 1 + null;#返回null


因为提成中含有null值,所以此刻不能直接使用sal+comm的方式获取携带提成的薪资。



图54coalesce转换后的结果

因为此时需要排除null字段,但若使用where语句排除,则可能会把不含提成的人连月薪都不进行统计了,所以此处需要使用前文提过的coalesce()函数将null值转换为0,SQL语句如下: 


select sal+coalesce(comm,0) from emp;


运行后,结果集如图54所示。

此时就可把工资与提成加到一起了,并且没有遗漏任何人,增加group by针对部门进行分组即可实现“每个部门的薪资最高与最低的人(携带提成)”的需求,SQL语句如下: 


//5.3 聚合函数.sql



select

deptno as '部门编号',

max(sal + coalesce(comm, 0)) as '部门最高薪资(携带提成)',

min(sal + coalesce(comm, 0)) as '部门最低薪资(携带提成)'

from

emp

group by

deptno;


运行后,结果集如图55所示。




图55最终结果


5.3.4查询每个部门的薪资总额

MySQL使用sum()函数记录相加后的总和,并且可通过group by针对emp表进行分组,这样便可获得每个部门的薪资总额,SQL语句如下: 


//5.3 聚合函数.sql



select

deptno as '部门编号',

sum(sal) as '部门的薪资总额'

from

emp

group by

deptno;


运行后,结果集如图56所示。




图56查询每个部门的薪资总额结果集


5.3.5查询每个部门有多少人

MySQL使用count()记录总行数,通过group by针对emp表进行分组,即可获得每个部门有多少人,SQL语句如下: 


//5.3 聚合函数.sql



select

deptno as '部门编号',

count(sal) as '总人数'

from

emp

group by

deptno;


运行后,结果集如图57所示。



图57查询每个部门有多少人的结果集


5.3.6查询每个部门有多少人没有提成

首先需要判断没有提成的人,即emp表中comm字段为空,然后因为需求中提到了需要根据每个部门进行分组,所以需要使用group by,最后需要使用count()函数统计人数,SQL语句如下: 


//5.3 聚合函数.sql



select

deptno as '部门名称',

count(ename) as '人数'

from

emp e

where

e.comm is null

or

e.comm = 0

group by

deptno;


运行后,结果集如图58所示。




图58查询每个部门有多少人没提成的结果集


5.3.7查询某个部门薪资占全公司的百分比

查询部门编号为10的部门,其薪资总额占全公司薪资总额的百分比,SQL语句如下: 


//5.3 聚合函数.sql



select

( select sum(e.sal) from emp e where e.deptno = 10 ) 

/

( select sum(e.sal) from emp e ) 

* 

100 

as result;


运行后,结果集如图59所示。



图59查询编号为10的部门薪资占全公司薪资百分比的结果集



当然此需求还有其他写法,例如使用后文将会提到的case when方式可以使用一条SQL语句就查询出来结果,SQL语句如下: 


//5.3 聚合函数.sql



select

(

sum(case when deptno = 10 then sal end) 

/

sum(sal)

) * 100 as pct

from

emp;


5.4窗口函数

在MySQL 8.0中推出了新的函数类型,即窗口类函数(Window Functions),窗口函数可对结果集中的每行进行计算,或使用与该行相关的行进行计算。

5.4.1窗口函数的语法

窗口函数的基本语法如下: 


//5.4 窗口函数.sql



<窗口函数> over (

partition by <用于分区的列名>

order by <用于排序的列名>

frame_clause <窗口大小>

)


如下SQL语句可在MySQL数据库中查询非聚合类窗口函数。之所以称Window Functions为非聚合类窗口函数,是因为在MySQL中聚合函数也可以作为窗口函数使用。


//5.4 窗口函数.sql



select

*

from

mysql.help_topic ht

where

ht.help_category_id = (

select

hc.help_category_id

from

mysql.help_category hc

where

hc.name = 'Window Functions'#窗口类型函数

);


MySQL中的非聚合类窗口函数统计如表52所示。


表52MySQL非聚合类窗口函数统计


函 数 名 称功能简易释义



cume_dist()cume_dist()函数返回值的累计分布值。该值小于或等于行的值除以总行数
dense_rank()分区内当前行的排名,无间隔
first_value()允许使用window frame获取分区或结果集第1行的值
lag()返回当前行之前的值
last_value()选择数据中的最后一行
lead()向前看多行并从当前行访问行的数据
nth_value()从有序行集中的第n行获取值
ntile()排序分区中的行并划分为特定数量的组。每个组分配一个分组号
percent_rank()百分比排名值
rank()分区内当前行的排名,有间隔
row_number()分区内的当前行数


5.4.2初步使用窗口函数

row_number()函数是最常用的窗口函数,row_number()函数可以给任意结果集增加序号和排序。查询emp全表的SQL语句如下: 


//5.4 窗口函数.sql



select 

e.ename,

e.job,

e.deptno,

e.sal 

from 

emp e;


运行后,结果集如图510所示。



图510初步使用窗口函数的结果集


此时可以通过row_number()函数增加行号列,SQL语句如下: 


//5.4 窗口函数.sql



select

row_number() over() as row_num,

e.ename,

e.job,

e.deptno,

e.sal

from

emp e;


运行后,结果集如图511所示。在该结果集中增加了row_num行号列。




图511增加row_num列的结果集


5.4.3partition by关键字

partition by用于将数据行拆分成多个分区,窗口函数基于每行数据所在的区进行计算并返回结果,partition by的作用类似于group by分组。若省略了 partition by关键字,则所有的数据作为一个组进行计算。

在增加行号的例子中,此时可以增加分区关键字,让行号根据部门编号(deptno)进行分区,SQL语句如下: 


//5.4.3 partition by关键字.sql



select

row_number() over(

partition by e.deptno

) as row_num,

e.ename,

e.job,

e.deptno,

e.sal






from

emp e;


运行后,结果集如图512所示。可以看到此时结果集根据部门编号进行了分区,以部门编号为10、20、30分为不同的区。每个区含有自身不同的行号。




图512根据部门编号进行分区的结果集


5.4.4order by关键字

order by排序用于指定分区内的排序方式,与select中的order by子句的作用类似,通常用于数据的排名分析。

在以上例子中,虽然使用了partition by关键字作为分区处理,但是因为分区之后每个部门并不是根据薪资(sal)高低进行排序的,所以此刻可以增加order by关键字,针对部门分区后进行排序,SQL语句如下: 


//5.4.4 order by关键字.sql



select

row_number() over(

partition by e.deptno

order by e.sal desc

) as row_num,

e.ename,

e.job,

e.deptno,

e.sal

from

emp e;


运行后,结果集如图513所示。




图513增加order by关键字的结果集


5.4.5rank()函数

rank()是一个窗口函数,rank()函数为分区或结果集中的每行分配排名,而排名值含有间隔。

此时可查询emp表中每名员工的薪资,SQL语句如下: 


//5.4.5 rank()函数.sql



select 

e.deptno,

e.ename,

e.sal

from 

emp e


运行后,结果集如图514所示。




图514查询emp表中每名员工的薪资的结果集


可通过rank()函数查询每个部门薪资的排序,SQL语句如下: 


//5.4.5 rank()函数.sql



select 

rank()over(

partition by e.deptno

order by sal desc

) as rank_num,

e.deptno,

e.ename,

e.sal

from 

emp e




图515通过rank()函数查询每个部门

薪资排序的结果集

运行后,结果集如图515所示。

此时可看出每个部门含有最高薪资的人,例如部门编号为10的薪资最高的人为王十二,部门编号为20的共有3人薪资最高,其薪资均为3000元。部门编号为20的薪资排行,没有第2名和第3名,只有第1名和第4名以后。此种排名方式被称为“含有间隔”排名。

rank()函数只能作为排序所存在,并不能直接获取rank_num列等于1的表达式,如想只获取rank_num薪资最高者,则需要在外再嵌套一层select查询语句,SQL语句如下: 


//5.4.5 rank()函数.sql



select

*

from

(

select

rank()over(

partition by e.deptno

order by

sal desc

) as rank_num,

e.deptno,

e.ename,

e.sal

from

emp e

) la

where

la.rank_num = 1;


运行后,结果集如图516所示。




图516获取每个部门薪资最高者的结果集


5.4.6dense_rank()函数

dense_rank()是一个窗口函数,dense_rank()函数为分区或结果集中的每行分配排名,而排名值没有间隔。

可以使用dense_rank()函数对部门进行分区以获取数据,查询每个部门的薪资排名,SQL语句如下: 


//5.4.6 dense_rank()函数.sql



select

e.deptno,

e.sal,

dense_rank()over(

partition by e.deptno

order by

e.sal desc

) as rnk

from

emp e;


运行后,结果集如图517所示。部门编号为20的组员薪资并列第1名的,rnk值皆为1,其低于第1名的为第2名。该排名方式被称作“没有间隔”。



图517体验“没有间隔”特性的结果集


之前的rank()函数,部门编号为20的组员工资并列第1名的,其rnk值皆为1,此时低于第1名的为第4名。该排名方式被称作“含有间隔”。

5.4.7percent_rank()函数

percent_rank()函数将会计算分区或结果集中行的百分位排名。例如此时可以使用percent_rank()函数查询每名员工占全公司薪资的百分位排名,SQL语句如下: 


//5.4.7 percent_rank()函数.sql



select

e.ename,

e.sal,

percent_rank() over (

order by

e.sal asc

) as '百分位排名'

from

emp e;


运行后,结果集如图518所示。




图518每名员工占全公司薪资的百分位排名的结果集


如果使用asc排序方式,则会让薪资最高的人排在最后,若使用desc排序方式,则会让薪资最低的人排在最后。

因为张十六的薪资在公司约77%的人之上,全公司共14人,所以张十六的薪资处于全公司约10名以上(14人×77%)。

由于赵六、寅十一、张十六的薪资并列,所以此3人的百分位均约为77%。

若嫌弃百分位小数过多,则可使用round()函数精确小数。本示例将百分位精确至2位小数即可,SQL语句如下: 


//5.4.7 percent_rank()函数.sql



select

e.ename,

e.sal,

round(

percent_rank()over (

order by

e.sal asc






),

2

) as '百分位排名'

from

emp e;


运行后,结果集如图519所示。




图519使用round()函数精确小数的结果集



5.4.8ntile()函数

ntile()函数可以辅助用户在分组后给每个分组增加一个编号,方便后续获取。ntile()函数的括号中需要输入一个正整数值n,在分组后,序号将会将n设置为最大值。

若使用了最大值的n之后还有分组没被增加编号的情况,则将会从1重新计数,即假设含有3个分组,但n被设置成了2,则含有分组编号为分组1、分组2、分组1。

若使用了一部分n之后没有分组需要使用编号了,则与正常展示无异。

例如,此时使用ntile()函数针对每个部门薪资总额分组后进行编号,SQL语句如下: 


//5.4.8 ntile()函数.sql



select

e.deptno,

sum(e.sal) sum_num,

ntile(3) over (

order by e.deptno

) group_no

from

emp e

group by

e.deptno


运行后,结果集如图520所示。




图520给分组增加编号的结果集



5.5聚合函数窗口化


所有的聚合函数均支持窗口化的使用方式,其中包括前文提到过的max()、min()、sum()、group_concat()等函数。只需在常规聚合函数之后增加over()子句。

窗口函数是MySQL中最特殊的函数形式,其特殊性在于窗口操作不会将查询行组折叠成单个输出行,相反窗口函数会为每行产生结果。

该特性在5.4节有所体现,此处可以使用两种sum()函数分别进行演示,分别为使用聚合函数和聚合函数窗口化的方式。

使用聚合函数查询全公司总月薪的SQL语句如下: 


select sum(sal) from emp;


运行后,结果集如图521所示。

使用聚合函数窗口化的方式查询全公司总月薪的SQL语句如下: 


select sum(sal) over() from emp;


运行后,结果集如图522所示。因为含有14个员工,所以其数字不会折叠,会展示出14行。




图521使用聚合函数查询全公司总月薪的结果集




图522聚合函数窗口化使数字不折叠的结果集





使用聚合函数查询公司内每个部门的平均薪资,SQL语句如下: 


select

deptno,

avg(sal) 

from

emp

group by

deptno;


运行后,结果集如图523所示。

使用聚合函数窗口化的方式查询公司内每个部门的平均薪资,SQL语句如下: 


select

deptno,

avg(sal) over(partition by deptno) as 'avg(sal)'

from

emp;


运行后,结果集如图524所示。




图523使用聚合函数查询公司内每个部门的平均薪资的结果集





图524以聚合函数窗口化的方式查询公司内每个部门的平均薪资的结果集




5.6MySQL 8.0处理数字相关的复杂查询

以下为有关MySQL处理数字相关的复杂查询与详解。




10min

5.6.1计算众数
1.  问题

众数的数学定义是“在给定数据集中出现频率最高的元素”,例如需要找出20号部门的员工薪水众数,SQL语句如下: 


select sal from emp where deptno = 20 order by sal;


运行后,计算众数之前的结果集如图525所示。计算众数之后的结果集如图526所示。




图525计算众数之前




图526计算众数之后




2. SQL演化

首先求出20号部门的各个阶层薪资及各阶层薪资的人数,SQL语句如下: 


//5.6.1 计算众数.sql



select

sal,

count(*) as cnt

from

emp

where

deptno = 20

group by

sal


运行后,结果集如图527所示。



图52720号部门的各个阶层薪资及各阶层薪资的人数的结果集


可以看出,月薪一共含有3个等级,分别是800、3000、1100,其中3000占的人数最多,含有3人,而后可根据各阶层薪资的人数cnt进行排序,SQL语句如下: 


//5.6.1 计算众数.sql



select

sal,

dense_rank() over(

order by

cnt desc

) as rnk

from






(

select

sal,

count(*) as cnt

from

emp

where

deptno = 20

group by

sal

) x;


运行后,结果集如图528所示,即薪资为3000等级的人数排第1位,800与1100等级的并列第2位。




图528根据分级薪资人数排序的结果集


最终获取排序rnk为1的数据即可,这就是部门编号为20的薪资里哪种薪资类型为最高,也就是找出了20号部门的员工薪资众数,SQL语句如下: 


//5.6.1 计算众数.sql



select

sal

from

(

select

sal,

dense_rank() over(

order by

cnt desc

) as rnk

from

(

select

sal,

count(*) as cnt

from

emp

where

deptno = 20

group by

sal

) x






) y

where

rnk = 1;





6min

5.6.2计算中值
1.  问题

中值的数学定义是: “中值(又称中位数)是指将统计总体中的各个变量值按大小顺序排列起来,形成一个数列,处于变量数列中间位置的变量值就称为中位数”,此时需要查出部门编号为20的员工薪资的中值是多少。

为计算中值,按照数学定义将部门编号为20的员工薪资的变量值按大小顺序排列起来,形成一个数列,SQL语句如下: 


//5.6.2 计算中值.sql



select

row_number() over (

order by e.sal

) row_num,

e.sal

from

emp e

where

e.deptno = '20'


运行后,计算中值之前的结果集如图529所示。计算中值之后的结果集如图530所示。




图529计算中值之前的结果集




图530计算中值之后的结果集




2.  SQL演化

获取部门编号为20的员工总数,并除以2获取中值的位置,SQL语句如下: 


//5.6.2 计算中值.sql



select

floor(count(e.sal) / 2) + 1

from

emp e

where

e.deptno = '20'


运行后,结果集如图531所示。




图531获取中值位置的结果集


拼接两条SQL语句。根据排列后的数列进行获取,只需获取row_num为3的薪资数目便可以查出部门编号为20的员工薪资的中值是多少,SQL语句如下: 


//5.6.2 计算中值.sql



select

*

from

(

select

row_number() over (

order by e.sal

) row_num,

e.sal

from

emp e

where

e.deptno = '20'

) as rum

where

rum.row_num = (

select

floor(count(e.sal) / 2) + 1

from

emp e

where

e.deptno = '20'

);