1. 程式人生 > >oracle利用分析函式row_number()over()查詢一張表所有欄位並按照其中部分欄位分組查詢某欄位最大值

oracle利用分析函式row_number()over()查詢一張表所有欄位並按照其中部分欄位分組查詢某欄位最大值

先準備資料:
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語句將獲得以下結果:
ROWNUMEMPID DEPTIDPARENT_DEPTIDSALARY
1**1101005500**
22102004500
33201001900
44202004800
55401006500
664020014500
774020044500
88501006500
99502007500


注意粗體部分,現在rownum 是1,
按如下sql來查:
select  rownum, te.* from test_employee te order by te.empid desc;
結果變成:
ROWNUMEMPID DEPTIDPARENT_DEPTIDSALARY
12102004500
23201001900
34202004800
45401006500
564020014500
674020044500
78501006500
89502007500


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 ;
將會得到如下結果:
RNEMPID DEPTIDPARENT_DEPTIDSALARY
11101005500
2210 2004500
23201001900
14202004800
35401006500
264020014500
174020044500
28501006500
19502007500






可以看出通過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;


RNEMPID DEPTIDPARENT_DEPTIDSALARY
11101005500
14202004800
174020044500
19502007500


如果想要得到薪水少的,只需要將分析函式中的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 ;


RNEMPID DEPTIDPARENT_DEPTIDSALARY
21101005500
**12102004500**
**13201001900**
24202004800
**15401006500**
264020014500
374020044500
**18501006500**
29502007500




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;


RNEMPID DEPTIDPARENT_DEPTIDSALARY
12102004500
13201001900
15401006500
18501006500


同理如果要使用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語句查出):
ROWNUMEMPID DEPTIDGENDER SALARY
1110 F5500
2210M 4500
3310M 1900
4410F4800
**5520 M 6500**
6620M 14500
7720F44500
**8820M 6500**
9920F7500




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;
結果如下:
RNEMPID DEPTIDGENDER SALARY
1110 F5500
1210M4500
1720F44500
1620 M14500




如果資料中同一分組存在兩條相同的排序資料,如何處理(如都為6500,M,20部分的),先改成資料如下:
ROWNUMEMPID DEPTIDGENDER SALARY
1110F5500
2210M4500
3310M1900
4410 F4800
5520M6500
6620M2500
7720F44500
8820M6500
9920F7500


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預設升序排序:
RNEMPID DEPTIDGENDER SALARY
1110F5500
1210M4500
1720F44500
**1520M6500**


做個測試,再salary 後再加個empid 降序排列,那麼是否應該empid=8的6500會被取出來?
查詢結果如下:
RNEMPID DEPTIDGENDER SALARY
1110F5500
1210M4500
1720F44500
**1820M6500**


結果如我所想empid=8的將會被取出來。


總結:
以上不能用group by,因為select 只能是group by後的欄位。


partition 是按部分欄位分組的意思。