笔记:Oracle SQL 高级查询简介 (1) case、层次化、扩展group by
1. 集合操作
union all 、 union、 intersect 、 minus
注意:集合操作的所有查询返回的列数、列类型必须相同,但是列名可以不一样。
2、translate 函数
translate(x, str1, str2) . 在字段x 中查找str1中的字符,转化为str2中对应的字符。
例子:
select translate(x, 'abc', 'xyz') from table1
对字段x中字符进行替换:a->x, b->y, x->z
3.DECODE() 函数
就是case 语句。
4、CASE 语句
搜索case表达式 例子:
select e.employee_id, case when e.salary>=10000 then 'good' when e.salary>5000 and e.salary < 10000 then 'middle' else 'poor' end as salary_type from hr.employees e
结果:
EMPLOYEE_ID SALARY_TYPE ----------- ----------- 100 good 101 good 102 good 103 middle 104 middle 105 poor 106 poor 107 poor 108 good
简单case表达式 例子:
select e.employee_id , case e.department_id when 90 then 'research' when 60 then 'sales' else 'unkown' end as department from hr.employees e
结果:
EMPLOYEE_ID DEPARTMENT ----------- ---------- 100 research 101 research 102 research 103 sales 104 sales 105 sales 106 sales 107 sales 108 unkown
5、层次化查询
使用 start with 和 connect to privor
select level , e.employee_id , e.manager_id, e.first_name||' '|| e.last_name as full_name from hr.employees e start with e.employee_id = 100 connect by prior e.employee_id = e.manager_id order by level
结果:
LEVEL EMPLOYEE_ID MANAGER_ID FULL_NAME ---------- ----------- ---------- ---------------------------------------------- 1 100 Steven King 2 102 100 Lex De Haan 2 114 100 Den Raphaely 2 120 100 Matthew Weiss 2 121 100 Adam Fripp 2 122 100 Payam Kaufling 2 123 100 Shanta Vollman 2 124 100 Kevin Mourgos 2 145 100 John Russell 2 146 100 Karen Partners 2 147 100 Alberto Errazuriz 2 148 100 Gerald Cambrault 2 149 100 Eleni Zlotkey 2 201 100 Michael Hartstein 2 101 100 Neena Kochhar 3 108 101 Nancy Greenberg 3 200 101 Jennifer Whalen 3 203 101 Susan Mavris 3 204 101 Hermann Baer 3 205 101 Shelley Higgins
添加过滤条件:
如
select level , e.employee_id , e.manager_id, e.first_name||' '|| e.last_name as full_name from hr.employees e where e.last_name != 'Kochhar' start with e.employee_id = 100 connect by prior e.employee_id = e.manager_id order by level
以上语句滤除了Kochhar这个人(id=101),但是Kochhar的下属还会出现在结果中:
LEVEL EMPLOYEE_ID MANAGER_ID FULL_NAME ---------- ----------- ---------- ---------------------------------------------- 1 100 Steven King 2 114 100 Den Raphaely 2 120 100 Matthew Weiss 2 121 100 Adam Fripp 2 122 100 Payam Kaufling 2 201 100 Michael Hartstein 2 124 100 Kevin Mourgos 2 145 100 John Russell 2 146 100 Karen Partners 2 147 100 Alberto Errazuriz 2 148 100 Gerald Cambrault 2 149 100 Eleni Zlotkey 2 102 100 Lex De Haan 2 123 100 Shanta Vollman 3 108 101 Nancy Greenberg 3 200 101 Jennifer Whalen 3 203 101 Susan Mavris 3 204 101 Hermann Baer 3 205 101 Shelley Higgins 3 103 102 Alexander Hunold
要一起滤除John 的下属,必须这样写
select level , e.employee_id , e.manager_id, e.first_name||' '|| e.last_name as full_name from hr.employees e start with e.employee_id = 100 connect by prior e.employee_id = e.manager_id and e.last_name != 'Kochhar' order by level
这样结果为:
LEVEL EMPLOYEE_ID MANAGER_ID FULL_NAME ---------- ----------- ---------- ---------------------------------------------- 1 100 Steven King 2 114 100 Den Raphaely 2 120 100 Matthew Weiss 2 121 100 Adam Fripp 2 122 100 Payam Kaufling 2 201 100 Michael Hartstein 2 124 100 Kevin Mourgos 2 145 100 John Russell 2 146 100 Karen Partners 2 147 100 Alberto Errazuriz 2 148 100 Gerald Cambrault 2 149 100 Eleni Zlotkey 2 102 100 Lex De Haan 2 123 100 Shanta Vollman 3 103 102 Alexander Hunold 3 115 114 Alexander Khoo 3 116 114 Shelli Baida 3 117 114 Sigal Tobias 3 118 114 Guy Himuro 3 119 114 Karen Colmenares
6. 扩展的Group By子句
(1). ROLLUP子句
为每一个分组返回一条记录,并为全部分组返回总计。
select e.department_id , avg(e.salary) from hr.employees e where e.department_id is not null group by rollup(e.department_id) ;
结果:
DEPARTMENT_ID AVG(E.SALARY) ------------- ------------- 10 4400 20 9500 30 4150 40 6500 50 3475.55555555 60 5760 70 10000 80 8955.88235294 90 19333.3333333 100 8601.33333333 110 10154 6456.75471698 12 rows selected
可以在多列上统计
select e.department_id , e.job_id, avg(e.salary) from hr.employees e where e.department_id is not null and e.job_id is not null group by rollup(e.department_id, e.job_id) ;
结果:
DEPARTMENT_ID JOB_ID AVG(E.SALARY) ------------- ---------- ------------- 10 AD_ASST 4400 10 4400 20 MK_MAN 13000 20 MK_REP 6000 20 9500 30 PU_MAN 11000 30 PU_CLERK 2780 30 4150 40 HR_REP 6500 40 6500 50 ST_MAN 7280 50 SH_CLERK 3215 50 ST_CLERK 2785 50 3475.55555555 60 IT_PROG 5760 60 5760 70 PR_REP 10000 70 10000 80 SA_MAN 12200 80 SA_REP 8396.55172413 80 8955.88235294 90 AD_VP 17000 90 AD_PRES 24000 90 19333.3333333 100 FI_MGR 12008 100 FI_ACCOUNT 7920 100 8601.33333333 110 AC_MGR 12008 110 AC_ACCOUNT 8300 110 10154 6456.75471698 31 rows selected
(2).CUBE
为每一个分组返回一条记录,并为全部小组组合返回总计,并给出统计。
select e.department_id , e.job_id, avg(e.salary) from hr.employees e where e.department_id is not null and e.job_id is not null group by cube(e.department_id, e.job_id) order by e.department_id, e.job_id;
结果:
DEPARTMENT_ID JOB_ID AVG(E.SALARY) ------------- ---------- ------------- 10 AD_ASST 4400 10 4400 20 MK_MAN 13000 20 MK_REP 6000 20 9500 30 PU_CLERK 2780 30 PU_MAN 11000 30 4150 40 HR_REP 6500 40 6500 50 SH_CLERK 3215 50 ST_CLERK 2785 50 ST_MAN 7280 50 3475.55555555 60 IT_PROG 5760 60 5760 70 PR_REP 10000 70 10000 80 SA_MAN 12200 80 SA_REP 8396.55172413 80 8955.88235294 90 AD_PRES 24000 90 AD_VP 17000 90 19333.3333333 100 FI_ACCOUNT 7920 100 FI_MGR 12008 100 8601.33333333 110 AC_ACCOUNT 8300 110 AC_MGR 12008 110 10154 AC_ACCOUNT 8300 AC_MGR 12008 AD_ASST 4400 AD_PRES 24000 AD_VP 17000 FI_ACCOUNT 7920 FI_MGR 12008 HR_REP 6500 IT_PROG 5760 MK_MAN 13000 MK_REP 6000 PR_REP 10000 PU_CLERK 2780 PU_MAN 11000 SA_MAN 12200 SA_REP 8396.55172413 SH_CLERK 3215 ST_CLERK 2785 ST_MAN 7280 6456.75471698 50 rows selected
(3). GROUPING 函数
接收一列,列为空则返回1,非空则返回0.
select grouping(e.department_id), e.department_id , avg(e.salary) from hr.employees e where e.department_id is not null group by rollup(e.department_id)
结果:
GROUPING(E.DEPARTMENT_ID) DEPARTMENT_ID AVG(E.SALARY) ------------------------- ------------- ------------- 0 10 4400 0 20 9500 0 30 4150 0 40 6500 0 50 3475.55555555 0 60 5760 0 70 10000 0 80 8955.88235294 0 90 19333.3333333 0 100 8601.33333333 0 110 10154 1 6456.75471698 12 rows selected
与case when 配合:
select case when grouping(e.department_id)=0 then ''||e.department_id else 'All Departments' end as department_id , case when grouping(e.job_id)=0 then e.job_id else 'All Jobs' end as job_id, avg(e.salary) from hr.employees e where e.department_id is not null and e.job_id is not null group by cube(e.department_id, e.job_id) order by e.department_id, e.job_id;
结果:
DEPARTMENT_ID JOB_ID AVG(E.SALARY) ---------------------------------------- ---------- ------------- 10 AD_ASST 4400 10 All Jobs 4400 20 MK_MAN 13000 20 MK_REP 6000 20 All Jobs 9500 30 PU_CLERK 2780 30 PU_MAN 11000 30 All Jobs 4150 40 HR_REP 6500 40 All Jobs 6500 50 SH_CLERK 3215 50 ST_CLERK 2785 50 ST_MAN 7280 50 All Jobs 3475.55555555 60 IT_PROG 5760 60 All Jobs 5760 70 PR_REP 10000 70 All Jobs 10000 80 SA_MAN 12200 80 SA_REP 8396.55172413 80 All Jobs 8955.88235294 90 AD_PRES 24000 90 AD_VP 17000 90 All Jobs 19333.3333333 100 FI_ACCOUNT 7920 100 FI_MGR 12008 100 All Jobs 8601.33333333 110 AC_ACCOUNT 8300 110 AC_MGR 12008 110 All Jobs 10154 All Departments AC_ACCOUNT 8300 All Departments AC_MGR 12008 All Departments AD_ASST 4400 All Departments AD_PRES 24000 All Departments AD_VP 17000 All Departments FI_ACCOUNT 7920 All Departments FI_MGR 12008 All Departments HR_REP 6500 All Departments IT_PROG 5760 All Departments MK_MAN 13000 All Departments MK_REP 6000 All Departments PR_REP 10000 All Departments PU_CLERK 2780 All Departments PU_MAN 11000 All Departments SA_MAN 12200 All Departments SA_REP 8396.55172413 All Departments SH_CLERK 3215 All Departments ST_CLERK 2785 All Departments ST_MAN 7280 All Departments All Jobs 6456.75471698 50 rows selected
(4). GROUPING SETS
grouping sets 只返回小计信息。
select e.department_id , e.job_id, avg(e.salary) from hr.employees e where e.department_id is not null and e.job_id is not null group by grouping sets(e.department_id, e.job_id) order by e.department_id, e.job_id;
结果:
DEPARTMENT_ID JOB_ID AVG(E.SALARY) ------------- ---------- ------------- 10 4400 20 9500 30 4150 40 6500 50 3475.55555555 60 5760 70 10000 80 8955.88235294 90 19333.3333333 100 8601.33333333 110 10154 AC_ACCOUNT 8300 AC_MGR 12008 AD_ASST 4400 AD_PRES 24000 AD_VP 17000 FI_ACCOUNT 7920 FI_MGR 12008 HR_REP 6500 IT_PROG 5760 MK_MAN 13000 MK_REP 6000 PR_REP 10000 PU_CLERK 2780 PU_MAN 11000 SA_MAN 12200 SA_REP 8396.55172413 SH_CLERK 3215 ST_CLERK 2785 ST_MAN 7280 30 rows selected
(5).GROUPING_ID 函数
相当于钱几个列的GROUPING值的组合。以下SQL
select grouping(e.department_id), grouping(e.job_id), grouping_id(e.department_id, e.job_id) as my_grouping_id, e.department_id , e.job_id, avg(e.salary) from hr.employees e where e.department_id is not null and e.job_id is not null group by cube(e.department_id, e.job_id) order by e.department_id, e.job_id;
返回:
GROUPING(E.DEPARTMENT_ID) GROUPING(E.JOB_ID) MY_GROUPING_ID DEPARTMENT_ID JOB_ID AVG(E.SALARY) ------------------------- ------------------ -------------- ------------- ---------- ------------- 0 0 0 10 AD_ASST 4400 0 1 1 10 4400 0 0 0 20 MK_MAN 13000 0 0 0 20 MK_REP 6000 0 1 1 20 9500 0 0 0 30 PU_CLERK 2780 0 0 0 30 PU_MAN 11000 0 1 1 30 4150 0 0 0 40 HR_REP 6500 0 1 1 40 6500 0 0 0 50 SH_CLERK 3215 0 0 0 50 ST_CLERK 2785 0 0 0 50 ST_MAN 7280 0 1 1 50 3475.55555555 0 0 0 60 IT_PROG 5760 0 1 1 60 5760 0 0 0 70 PR_REP 10000 0 1 1 70 10000 0 0 0 80 SA_MAN 12200 0 0 0 80 SA_REP 8396.55172413 0 1 1 80 8955.88235294 0 0 0 90 AD_PRES 24000 0 0 0 90 AD_VP 17000 0 1 1 90 19333.3333333 0 0 0 100 FI_ACCOUNT 7920 0 0 0 100 FI_MGR 12008 0 1 1 100 8601.33333333 0 0 0 110 AC_ACCOUNT 8300 0 0 0 110 AC_MGR 12008 0 1 1 110 10154 1 0 2 AC_ACCOUNT 8300 1 0 2 AC_MGR 12008 1 0 2 AD_ASST 4400 1 0 2 AD_PRES 24000 1 0 2 AD_VP 17000 1 0 2 FI_ACCOUNT 7920 1 0 2 FI_MGR 12008 1 0 2 HR_REP 6500 1 0 2 IT_PROG 5760 1 0 2 MK_MAN 13000 1 0 2 MK_REP 6000 1 0 2 PR_REP 10000 1 0 2 PU_CLERK 2780 1 0 2 PU_MAN 11000 1 0 2 SA_MAN 12200 1 0 2 SA_REP 8396.55172413 1 0 2 SH_CLERK 3215 1 0 2 ST_CLERK 2785 1 0 2 ST_MAN 7280 1 1 3 6456.75471698 50 rows selected
GROUPING_ID 与having 联合使用,可以过滤出想需要的统计值。
(6). GROUP_ID
在group by 中可以多次使用同一列,这样可以实现对数据的重新组织,或者按照不同的数据分组进行统计。
select e.department_id , e.job_id, avg(e.salary) from hr.employees e where e.department_id is not null and e.job_id is not null group by e.department_id, rollup(e.department_id, e.job_id)
结果:
DEPARTMENT_ID JOB_ID AVG(E.SALARY) ------------- ---------- ------------- 10 AD_ASST 4400 20 MK_MAN 13000 20 MK_REP 6000 30 PU_MAN 11000 30 PU_CLERK 2780 40 HR_REP 6500 50 ST_MAN 7280 50 SH_CLERK 3215 50 ST_CLERK 2785 60 IT_PROG 5760 70 PR_REP 10000 80 SA_MAN 12200 80 SA_REP 8396.55172413 90 AD_VP 17000 90 AD_PRES 24000 100 FI_MGR 12008 100 FI_ACCOUNT 7920 110 AC_MGR 12008 110 AC_ACCOUNT 8300 10 4400 20 9500 30 4150 40 6500 50 3475.55555555 60 5760 70 10000 80 8955.88235294 90 19333.3333333 100 8601.33333333 110 10154 10 4400 20 9500 30 4150 40 6500 50 3475.55555555 60 5760 70 10000 80 8955.88235294 90 19333.3333333 100 8601.33333333 110 10154
结果中有重复的分组,可以使用GROUP_ID消除。
group_id 不接受任何参数,如果某个特定的分组出现n次,那么grouo_id返回从0到n-1之间的整数。
如改写以上SQL为:
select e.department_id , e.job_id, group_id(), avg(e.salary) from hr.employees e where e.department_id is not null and e.job_id is not null group by e.department_id, rollup(e.department_id, e.job_id)
结果为:
DEPARTMENT_ID JOB_ID GROUP_ID() AVG(E.SALARY) ------------- ---------- ---------- ------------- 10 AD_ASST 0 4400 20 MK_MAN 0 13000 20 MK_REP 0 6000 30 PU_MAN 0 11000 30 PU_CLERK 0 2780 40 HR_REP 0 6500 50 ST_MAN 0 7280 50 SH_CLERK 0 3215 50 ST_CLERK 0 2785 60 IT_PROG 0 5760 70 PR_REP 0 10000 80 SA_MAN 0 12200 80 SA_REP 0 8396.55172413 90 AD_VP 0 17000 90 AD_PRES 0 24000 100 FI_MGR 0 12008 100 FI_ACCOUNT 0 7920 110 AC_MGR 0 12008 110 AC_ACCOUNT 0 8300 10 0 4400 20 0 9500 30 0 4150 40 0 6500 50 0 3475.55555555 60 0 5760 70 0 10000 80 0 8955.88235294 90 0 19333.3333333 100 0 8601.33333333 110 0 10154 10 1 4400 20 1 9500 30 1 4150 40 1 6500 50 1 3475.55555555 60 1 5760 70 1 10000 80 1 8955.88235294 90 1 19333.3333333 100 1 8601.33333333 110 1 10154
与HAVING 子句联合使用,则可以消除重复的列。