oracle函数,多表查询
1. 函数
函数一般是在数据上执行的,它给数据的转换和处理提供了方便。只是将取出的数据进行处理,不会改变数据库中的值。
函数根据处理的数据分为单行函数和聚合函数(组函数)
组函数又被称作聚合函数,用于对多行数据进行操作,并返回一个单一的结果,组函数仅可用于选择列表或查询的having子句
单行函数对单个数值进行操作,并返回一个值。
dual是一个系统表。注意用于测试。
2.字符相关
1 -- dual用于测试 2 3 select * from dual; 4 5 6 7 -- 1.字符串连接 8 9 selectconcat('aa','12') from dual; 10 11 select'aa'||'12'from dual; 12 13 14 15 -- 2.首字母大写 16 17 selectinitcap('abc') from dual; 18 19 --- 把大写转化小写 20 21 selectlower('ABc') from dual; 22 23 selectupper('abc') from dual; 24 25 26 27 -- 把所有员工的姓名小写输出 28 29 selectlower(e.ename),e.empno 30 31 from emp e 32 33 34 35 -- 3.填充字符lpad/rpad 36 37 selectlpad('sxt',5,'*') from dual; 38 39 selectrpad('sxt',5,'*') from dual; 40 41 42 43 -- 4.去掉空白字符 44 45 select' kallen'from dual; 46 47 selectltrim(' kallen',' ') from dual; 48 49 selectrtrim(' kallen ',' ') from dual; 50 51 -- trim 删除左右两边的字符 52 53 selecttrim('a'from'abc') from dual; 54 55 56 57 -- 5.求子串 substr(str,loc,len)-->loc从1开始 58 59 selectsubstr('abcd',2,2) from dual; 60 61 62 63 -- 6.查找字符串 64 65 /* 66 67 如果找到返回>=1的索引;如果没找到返回0 68 69 */ 70 71 selectinstr('abcd','b') from dual; 72 73 74 75 -- 7.求长度 76 77 selectlength('abcd') from dual;
需求:格式化电话号码
selectsubstr('18612341234',1,3)||'-'||substr('18612341234',4,4)||'-'||substr('18612341234',8,4) from dual;
3. 数值型函数
1 -- 数值型函数 2 3 -- 四舍五入round(x,y)对x保留y为小数 4 5 selectround(23.652) from dual; 6 7 selectround(23.652,1) from dual; 8 9 selectround(25.652,-1) from dual; 10 11 12 13 -- 返回x按精度y截取后的值 14 15 selecttrunc(23.652) from dual; 16 17 selecttrunc(23.652,2) from dual; 18 19 selecttrunc(23.652,-1) from dual; 20 21 22 23 -- mod(x,y)求余数 24 25 selectmod(9,2) from dual; 26 27 28 29 -- ceil 向上取整 30 31 selectceil(1.9) from dual; 32 33 -- floor 向下取整 34 35 selectfloor(1.9) from dual;
4. 日期时间函数
1) 日期函数
1 -- 返回系统当前时间 2 3 selectsysdatefrom dual; 4 5 -- 返回当前会话时区中的当前日期 6 7 select current_date from dual; 8 9 10 11 -- 添加月数 12 13 select add_months(sysdate,1) from dual; 14 15 -- 返回两个时间相差的月数 16 17 select months_between(sysdate,add_months(sysdate,2)) from dual; 18 19 20 21 -- 需求:查询工作年限在30年以上 22 23 select e.ename,e.hiredate 24 25 from emp e 26 27 where months_between(sysdate,e.hiredate)/12>30 28 29 30 31 -- 返回date所在月份最后的一天 32 33 select last_day(add_months(sysdate,1)) from dual; 34 35 -- next_day(date1,week) 返回date1下周星期几的日期 36 37 selectsysdate "当时日期",next_day(sysdate,'Monday') "下周星期一" from dual; 38 39 40 41 -- 查询会话的环境参数 42 43 select * from nls_session_parameters;
2) 日期计算相关
selectsysdate+2from dual; selectsysdate-2from dual;
两个时间进行四则运算的单位是天。
5. 转换函数
转换函数就是把字符、日期、数值型数据进行相互转换。类型转换分两种:隐式类型转换和显式类型转换
1) 隐式类型转换
字符和数字/日期之间的隐式转换
1 -- 字符隐式转换成数值 2 3 select'100' - 10from dual; 4 5 6 7 -- 字符隐式转化为日期 8 9 -- DD-MON-RR 默认的日期格式 10 11 select1from dual 12 13 wheresysdate>'13-May-19'; 14 15 16 17 -- 查date format格式 18 19 select * from nls_session_parameters;
2) 显示类型转换
|
[1] to_char
把日期转化成字符
|
把数值格式化成字符串
|
1 -- to_char 2 3 -- 【1】把日期转化成字符 4 5 -- 按照默认格式DD-MON-RR 6 7 select to_char(sysdate) from dual; 8 9 -- 按指定格式 10 11 select to_char(sysdate,'YYYY"年"MM"月"DD"日" HH24:MI:SS') as t from dual; 12 13 14 15 -- 【2】把数值格式化成字符串 16 17 select to_char(12345,'99999.99') from dual; 18 19 select to_char(12345,'99,999.99') from dual; 20 21 select to_char(12345,'999,999.99') from dual; 22 23 -- 不够位置0 24 25 select to_char(12345,'000,000.00') from dual; 26 27 -- 格式化成美元显示 28 29 select to_char(12345,'$000,000.00') from dual;
需求:把18612341234格式化成186-1234-1234
-- 需求:把18612341234格式化成186-1234-1234 selectreplace(to_char(18612341234,'999,9999,9999'),',','-') from dual;
[2] to_number、to_date
-- to_number select to_number('$12,345','$99,999') from dual; select to_number('$12,345.12','$99,999.99') from dual; -- to_date select to_date('14-May-19','DD-MON-RR') from dual; select to_date('2004-09-19','YYYY-MM-DD') from dual;
函数可以嵌套
1 -- 查询雇用期满6个月的下一个周一的日期。 2 3 select e.ename,e.hiredate,next_day(add_months(e.hiredate,6),'Monday') 4 5 from emp e 6 7 where months_between(sysdate,e.hiredate) >6 8 9 10 11 -- 查询公司boss 12 13 select e.ename || nvl(to_char(e.mgr),' is boss') 14 15 from emp e 16 17 where e.mgr isnull
6. decode/case when
decode(条件,值1,“返回值1”,值2,“返回值2”,,,“默认值”)
1 -- 需求:查询员工所在的部门名称 2 3 select 4 5 e.ename, 6 7 e.deptno, 8 9 decode(e.deptno,10,'部门1',20,'部门2',30,'部门3','未知') 10 11 from emp e;

case when
1 -- case when 2 3 select 4 5 e.ename, 6 7 e.deptno, 8 9 case e.deptno 10 11 when10then'部门1' 12 13 when20then'部门2' 14 15 when30then'部门3' 16 17 else'未知' 18 19 end 20 21 from emp e;
1 -- 需求:对各个部门进行涨薪,10->1.1 20->1.2 30->1.3 其他->1.0 2 3 select 4 5 e.deptno, 6 7 e.ename, 8 9 e.sal "涨薪前", 10 11 decode(e.deptno,10,e.sal*1.1,20,e.sal*1.2,30,e.sal*1.3,e.sal) "涨薪后" 12 13 from emp e 14 15 16 17 -- 需求:根据工资分布输出以下信息 18 19 /* 20 21 <1000 真屌丝 22 23 (1001,2000] 屌丝 24 25 (2001,3000] 白领 26 27 (3001,5000] 高富帅 28 29 (5001,10000] 土豪 30 31 */ 32 33 34 35 select 36 37 e.ename "姓名", 38 39 e.sal "工资", 40 41 case 42 43 when e.sal <= 1000then'真屌丝' 44 45 when e.sal <= 2000then'屌丝' 46 47 when e.sal <= 3000then'白领' 48 49 when e.sal <= 5000then'高富帅' 50 51 when e.sal <= 10000then'土豪' 52 53 else'未知' 54 55 end "描述" 56 57 from emp e;
decode多用于等值匹配;case when可以用于等值,多用于条件分支。
7. 组函数
组函数把多行数据经过运算后返回单个值。也称聚合函数。
|
1 -- 求公司雇员的数量 2 3 selectcount(*) 4 5 from emp e; 6 7 8 9 selectcount(e.empno) 10 11 from emp e; 12 13 14 15 selectcount(1) 16 17 from emp e; 18 19 20 21 -- avg:对多个记录的某个字段求平均值 22 23 -- 需求:求底薪的平均值 24 25 selectavg(e.sal) 26 27 from emp e; 28 29 30 31 32 33 -- 需求:求雇员的最高薪资/最低薪资 34 35 selectmax(e.sal),min(e.sal),avg(e.sal) 36 37 from emp e; 38 39 40 41 -- 需求:求公司一个月的员工基本开销 42 43 selectsum(e.sal) 44 45 from emp e;
注意:
[1] 组函数或聚合函数是对一个数据集(表数据、查询出来的表、分组的表)进行聚合。
[2]聚合函数对字段是null的值进行忽略。count(*)
-- 求有津贴的员工的数量 selectcount(e.comm) from emp e;
[3] max/min 适合任意数据类型,sum/avg 只适用于数值类型。
聚合函数的结果可以作为其他查询条件。
-- 最早入职的员工 select e.ename,e.hiredate from emp e where e.hiredate = (selectmin(e.hiredate) from emp e);
8. 分组(group by)
在处理统计或聚合数据时,很多时候需要对数据进行分组语法
select field1,。。。 from tableName group by field1[,field2,…]
按照field1[,field2,…]分组,字段值相同的记录分到一组。
1) groupby的工作原理
|
对数据进行分组后,select语句的字段值只能是分组字段或者聚合函数。
2)分组和聚合函数
-- 需求:求各个部门的人数 select e.deptno from emp e group by e.deptno;
1 -- 需求:统计部门10的人数 2 3 select count(1) 4 5 from emp e 6 7 where e.deptno = 10; 8 9 10 11 12 13 14 15 -- 需求:求各个部门的人数 16 17 select e.deptno,e.ename 18 19 from emp e 20 21 group by e.deptno; 22 23 24 25 -- 需求:求各个部门的平均薪资 26 27 select e.deptno,avg(e.sal) 28 29 from emp e 30 31 group by e.deptno 32 33 34 35 -- 需求:求各个部门的月收入平均值 36 37 select e.deptno,avg(e.sal+nvl(e.comm,0)) 38 39 from emp e 40 41 group by e.deptno
3) null值归为一组
1 -- 特例:按照津贴分组 2 3 select e.comm,count(1) 4 5 from emp e 6 7 group by e.comm

4) having
如果需要对分组的数据进行条件过滤,必须使用having!!!
1 -- group by having 2 3 -- 查询部门平均薪资大于3000的部门 4 5 select e.deptno 6 7 from emp e 8 9 group by e.deptno 10 11 having avg(e.sal) >3000 12 13 14 15 -- 查询部门薪资大于3000的雇员按部门分组的平均薪资 16 17 select e.deptno,avg(e.sal) 18 19 from emp e 20 21 where e.sal >3000 22 23 group by e.deptno;
注意:
[1]Where过滤行(字段),having过滤分组。
[2] Having支持所有where操作符。
9. 排序 (order by)
当需要对数据集进行排序操作时,语法
select field1, field2,。。。 from tablename order by field1,field2
对数据集进行排序,先按field1排序,如果field1排序相同,按照field2排序,依次类推。
-asc 升序,默认
-desc 降序
1 -- order by 2 3 -- 需求:按雇员薪资排序 4 5 6 7 select e.ename,e.sal 8 9 from emp e 10 11 orderby e.sal desc 12 13 14 15 -- 按薪资升序,名称降序 16 17 select e.ename,e.sal 18 19 from emp e 20 21 orderby e.sal,e.ename desc;
order by 一般都是最后执行。
需求:查询薪资大于1200的雇员在部门中平均薪资大于1500的部门,按照平均薪资升序排序。
1 --薪资大于1200的雇员所在部门的平均薪资大于1500的部门,按照平均薪资升序排序 2 3 4 5 -- [1] 查询薪资大于1200的雇员 6 7 select e.* 8 9 from emp e 10 11 where e.sal >1200 12 13 14 15 -- [2]按部门分组 16 17 select e.* 18 19 from emp e 20 21 where e.sal >1200 22 23 groupby e.deptno 24 25 26 27 -- [3] 输出聚合结果 28 29 select e.deptno,avg(e.sal) 30 31 from emp e 32 33 where e.sal >1200 34 35 groupby e.deptno 36 37 havingavg(e.sal) >1500 38 39 40 41 -- [4]对数据集进行排序 42 43 select e.deptno,avg(e.sal) 44 45 from emp e 46 47 where e.sal >1200 48 49 groupby e.deptno 50 51 havingavg(e.sal) >1500 52 53 orderbyavg(e.sal) asc
orderby既可以用于数据行(记录)排序。
也可以对分组的结果进行排序,此时需要聚合函数配合。
10. Select语言的执行顺序
|
from -> where -> group by -> having -> select -> order by
11. 交集、全集、并集、差集
并集:把集合A的结果和集合B的结果合并,并去掉重复的记录。
1 -- 并集 2 3 select e.* from emp e where e.deptno = 10 4 5 union 6 7 select e.* from emp e where e.deptno = 20; 8 9 10 11 -- 有重复记录取并集 12 13 select e.* from emp e where e.deptno = 10or e.deptno = 20 14 15 union 16 17 select e.* from emp e where e.deptno = 20;
全集:把集合A的结果和集合B的结果合并,保留重复记录
select e.* from emp e where e.deptno = 10 or e.deptno = 20 union all select e.* from emp e where e.deptno = 20;
交集:把集合A的结果和集合B的结果取相同部门
select e.* from emp e where e.deptno = 10or e.deptno = 20 intersect select e.* from emp e where e.deptno = 10;
差集:在集合A的结果中去掉集合B的结果 (A-B)
select e.* from emp e where e.deptno = 10or e.deptno = 20 minus select e.* from emp e where e.deptno = 10;
12. 多表关联
1) 笛卡尔积
|
|
-- 笛卡尔积 select * from emp,dept |
2) 等值连接
1 -- 等值连接 2 3 -- 需求:查询雇员的部门名称 4 5 select e.ename,e.deptno,d.dname 6 7 from emp e,dept d 8 9 where e.deptno = d.deptno
3) 不等值连接
1 -- 不等值连接 2 3 -- 查询每个雇员的薪资等级 4 5 select e.ename,e.sal,sg.grade 6 7 from emp e,salgrade sg 8 9 where e.sal >= sg.losal and e.sal <= sg.hisal 10 11 -- where e.sal between sg.losal and sg.hisal
4) 外连接
左外连接:左边的表作为主表,右边表作为从表,主表数据都显示,从表数据没有,用null填充,用+号表示。
1 -- 左外连接(B) 2 3 -- 需求:查询所有部门的雇员 4 5 select * 6 7 from dept d,emp e 8 9 where d.deptno = e.deptno(+)
右外连接:右边的表作为主表,左边表作为从表,主表数据都显示,从表数据没有,用null填充,用+号表示。
1 -- 右外连接(B) 2 3 select * 4 5 from emp e,dept d 6 7 where e.deptno(+) = d.deptno;
5) 自连接
一个表自身连接自身时,称为自连接。自连接以不同的视角看待同一张表。
1 -- 查询每个雇员的上级领导 2 3 select e.ename "雇员",m.ename "领导" 4 5 from emp e,emp m 6 7 where e.mgr = m.empno 8 9 10 11 -- 优化king 12 13 select e.ename "雇员",nvl(m.ename,'boss') "领导" 14 15 from emp e,emp m 16 17 where e.mgr = m.empno(+)
6) 多于两张表的查询
如果有多个表参与查询,先把t1xt2笛卡尔积得到一个大表T1,再把T1xt3笛卡尔积得到一个另外的大表T2,依次类推。
所有的多表查询最终都是两种表的查询。
13. 多表关联 - 99 语法
92的问题:
[1]表的过滤条件和表的连接条件混合在一起,维护麻烦
[2]数据库的数据适合变化,根据where子句的执行规则,sql语言也会相应发生变化,给维护造成一定成本。
1) 笛卡尔积
table 1 cross join table2
-- 99 笛卡尔积 select * from dept d crossjoin emp e
2) 自然连接
NATURAL JOIN子句基于两个表中列名完全相同的列产生连接
[1]两个表有相同名字的列
[2]数据类型相同
[3]从两个表中选出连接列的值相等的所有行
-- [2]自然连接 select * from dept d naturaljoin emp e
|
自然连接只保留一个重复列,整个数据集只有一个deptno。
注意:
自然连接最优的使用场景是:主外键关系且主外键字段只有一个。
3) using
using 主要用于指定连接字段。
[1]按照指定的字段连接两个表。
[2] 选指定字段值相同的数据行。
using同样适用于自然连接。
4) on指定连接条件
自然连接的条件是基于表中所有同名列的等值连接
为了设置任意的连接条件或者指定连接的列,需要使用ON子句
连个表的关联用关键字join ,默认内连接(inner) 语法
select filed1,fild2,… from table1 join table2 on condition1 [join table3 on condition2]*
-- 查询出员工的部门名称 select * from dept d join emp e on d.deptno = e.deptno
-- 查询scott的上级领导 select e.ename,m.ename from emp e join emp m on e.mgr = m.empno where e.ename = 'SCO%T'
使用join on语句连接3张表
-- 查询SCO%T部门名称和薪资等级 select e.ename,d.dname,sg.grade from dept d join emp e on d.deptno = e.deptno join salgrade sg on e.sal between sg.losal and sg.hisal where e.ename = 'SCO%T'
-- 查询SCO%T的管理者名称和其管理者的薪资等级 select e.ename,m.ename,sg.grade from emp e join emp m on e.mgr = m.empno join salgrade sg on m.sal between sg.losal and sg.hisal where e.ename = 'SCO%T'
5) 外连接
外连接在99语法中通过outer 关键字,按照主从表的位置可以分为left outer/right outer,语法
select filed1,field2 from table1 left/right outer join table2 on condition1 [left/right outer join table3 on condition2]*
左外连接
-- 查询所有部门的所有员工 select * from dept d leftouterjoin emp e on d.deptno = e.deptno
右外连接
-- 查询所有部门的所有员工 select * from emp e rightouterjoin dept d on e.deptno = d.deptno;
浙公网安备 33010602011771号