您的位置:首页 > 数据库 > Oracle

oracle利用分析函数row_number()over()查询一张表所有字段并按照其中部分字段分组查询某字段最大值

2016-10-23 13:28 856 查看
先准备数据:

deptid :部门id.

parent_deptid :deptid 的父级部门,也就是depid 是他的子部门。

create table test_employee (empid int ,deptid int ,parent_deptid int,salary decimal(10,2));

insert into test_employee values(1,10,100,5500.00);

insert into test_employee values(2,10,200,4500.00);

insert into test_employee values(3,20,100,1900.00);

insert into test_employee values(4,20,200,4800.00);

insert into test_employee values (5, 40,100, 6500.00);

insert into test_employee values (6, 40,200, 14500.00);

insert into test_employee values (7, 40,200, 44500.00);

insert into test_employee values (8, 50,100, 6500.00);

insert into test_employee values (9, 50,200, 7500.00);

假设说存在这么一个需求,需要获得所有子部门里薪水最高的那部分员工,

需要显示的字段有 empid, deptid,parent_deptid, salary

先简单介绍下这个sql中会遇到的一些关键的点:

1.row_number

select  rownum, te.* from test_employee te ;

以上sql语句将获得以下结果:

ROWNUM EMPID
DEPTID PARENT_DEPTID
SALARY

1 **1 10
100 5500**

2 2 10
200 4500

3 3 20
100 1900

4 4 20
200 4800

5 5 40
100 6500

6 6 40
200 14500

7 7 40
200 44500

8 8 50
100 6500

9 9 50
200 7500

注意粗体部分,现在rownum 是1,

按如下sql来查:

select  rownum, te.* from test_employee te order by te.empid desc;

结果变成:

ROWNUM EMPID
DEPTID PARENT_DEPTID
SALARY

1 2 10
200 4500

2 3 20
100 1900

3 4 20
200 4800

4 5 40
100 6500

5 6 40
200 14500

6 7 40
200 44500

7 8 50
100 6500

8 9 50
200 7500

empid为1 的记录不见了,但rownum 仍旧从1开始,也就说

rownum实际上就是查询自结果的一个逻辑排序。

2.利用分析函数(oracle)**row_number()以及**over()来分组筛选出符合条件的记录,注意在当rownumber与over()配合使

用时,是写法不一样的,注意粗体部分。

执行以下sql:

select  row_number()over(partition by te.deptid order by te.salary desc) rn, te.* from test_employee te order by 

empid ;

将会得到如下结果:

RN EMPID
DEPTID PARENT_DEPTID
SALARY

1 1 10
100 5500

2 2 10 200
4500

2 3 20
100 1900

1 4 20
200 4800

3 5 40
100 6500

2 6 40
200 14500

1 7 40
200 44500

2 8 50
100 6500

1 9 50
200 7500

可以看出通过row_number()over(partition by te.deptid order by te.salary desc) rn这个分析函数已经通过deptid来分组

并通过薪水

来降序排列,那么在这个分组里薪水高的row_number将会是1,之后的

依次往后累加1,然后在通过查询以上上这个结果集,并加上条件rn=1

就能查出薪水最高的那位了,sql如下:

select * from (select  row_number()over(partition by te.deptid order by te.salary desc) rn, te.* from 

test_employee te)t1 where rn=1;

RN EMPID
DEPTID PARENT_DEPTID
SALARY

1 1 10
100 5500

1 4 20
200 4800

1 7 40
200 44500

1 9 50
200 7500

如果想要得到薪水少的,只需要将分析函数中的order by desc 改成asc即可,那么薪水最低的RN 将会是1

select  row_number()over(partition by te.deptid order by te.salary asc) rn, te.* from test_employee te order by 

empid ;

RN EMPID
DEPTID PARENT_DEPTID
SALARY

2 1 10
100 5500

**1 2 10
200 4500**

**1 3 20
100 1900**

2 4 20
200 4800

**1 5 40
100 6500**

2 6 40
200 14500

3 7 40
200 44500

**1 8 50
100 6500**

2 9 50
200 7500

select * from (select  row_number()over(partition by te.deptid order by te.salary asc) rn, te.* from 

test_employee te)t1 where rn=1;

RN EMPID
DEPTID PARENT_DEPTID
SALARY

1 2 10
200 4500

1 3 20
100 1900

1 5 40
100 6500

1 8 50
100 6500

同理如果要使用2个或以上字段来进行分组,上面的数据有点不对,一个

小部分只能属于一个大部门,稍微改下数据:

drop table test_employee;

create table test_employee (empid int ,deptid int ,gender varchar(1),salary decimal(10,2));

insert into test_employee values(1,10,'F',5500.00);

insert into test_employee values(2,10,'M',4500.00);

insert into test_employee values(3,10,'M',1900.00);

insert into test_employee values(4,10,'F',4800.00);

insert into test_employee values (5, 20,'M', 6500.00);

insert into test_employee values (6, 20,'M', 14500.00);

insert into test_employee values (7, 20,'F', 44500.00);

insert into test_employee values (8, 20,'M', 6500.00);

insert into test_employee values (9, 20,'F', 7500.00);

如假设存在以下条件,找出部门里的男女员工各自的最高薪(用一个sql语句查出):

ROWNUM EMPID
DEPTID GENDER
SALARY

1 1 10 F
5500

2 2 10
M 4500

3 3 10
M 1900

4 4 10
F 4800

**5 5 20 M 6500**

6 6 20
M 14500

7 7 20
F 44500

**8 8 20
M 6500**

9 9 20
F 7500

select * from (select  row_number()over(partition by te.deptid,gender order by te.salary desc) rn, te.* from 

test_employee te)t1 where rn=1;

结果如下:

RN EMPID
DEPTID GENDER
SALARY

1 1 10 F
5500

1 2 10
M 4500

1 7 20
F 44500

1 6 20 M
14500

如果数据中同一分组存在两条相同的排序数据,如何处理(如都为6500,M,20部分的),先改成数据如下:

ROWNUM EMPID
DEPTID GENDER
SALARY

1 1 10
F 5500

2 2 10
M 4500

3 3 10
M 1900

4 4 10 F
4800

5 5 20
M 6500

6 6 20
M 2500

7 7 20
F 44500

8 8 20
M 6500

9 9 20
F 7500

select * from (select  row_number()over(partition by te.deptid,gender order by te.salary desc) rn, te.* from 

test_employee te)t1 where rn=1;

 如下,empid=5 的被取出来了,原因是第一排序是salary,之后按empid默认升序排序:

RN EMPID
DEPTID GENDER
SALARY

1 1 10
F 5500

1 2 10
M 4500

1 7 20
F 44500

**1 5 20
M 6500**

做个测试,再salary 后再加个empid 降序排列,那么是否应该empid=8的6500会被取出来?

查询结果如下:

RN EMPID
DEPTID GENDER
SALARY

1 1 10
F 5500

1 2 10
M 4500

1 7 20
F 44500

**1 8 20
M 6500**

结果如我所想empid=8的将会被取出来。

总结:

以上不能用group by,因为select 只能是group by后的字段。

partition 是按部分字段分组的意思。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  oracle sql 分析函数