3. 单行函数
3.1 转换函数
select ascii('A'),chr(65) from dual;
select to_char(1243123),1231451 from dual;
靠左边的就是字符串,靠右边的就是数字
select to_char(123512a121) from dual; --错误的写法,没有引号表示数字,但是数字里面包含了字母,不合法的输入值
select to_number('123141211') from dual;
select to_number('12314a1211') from dual; --不合法的输入值
select to_date('20140610121212','yyyy-mm-dd hh24:mi:ss') from dual;
不合法的输入值:
select to_date('20141310121212','yyyy-mm-dd hh24:mi:ss') from dual;
select to_date(20140610121212,'yyyy-mm-dd hh24:mi:ss') from dual; --日期不加引号,数字类型
将日期转换为固定格式字符串
select to_char(sysdate,'yyyy/mm/dd hh24:mi:ss') from dual;
select to_char(sysdate,'yyyymmdd') from dual;
select to_number(to_char(sysdate,'yyyymmdd')) from dual;
3.2 字符串的运算
(1)字符串的连接
select concat('123124','asdfda') from dual; --只能传两个参数,但是||可以不断拼接
select '123124'||'asdfda' from dual;
(2)求长度
select length('adsfasgsadfasdf') from dual;
(3)截取串
select substr('asdfasdfasdfasdf',5,4) from dual;
从左向右第5位开始向后截取4个字节长度
select substr('asdfasdfasdfasdf',-5,4) from dual;
从右向左第5位开始向后截取4个字节长度
select length(substr('asdfasdfasdfasdf',-5,7)) from dual; --截取完为止
(4)求子串的位置
select instr('asdfasdfasdfasdf','asdf',3,1) from dual;
从左向右第3位开始,第1次出现‘asdf’的索引位置
select instr('asdfasdfasdfasdf','asdf',3,2) from dual;
从左向右第3位开始,第2次出现‘asdf’的索引位置
select instr('asdfasdfasdfasdf','asdf',-3,2) from dual; --9 (红色的为第一个,***开始为第二个,也就是第五个a是第二个,然后顺序再从右边第四个开始算起为1,所以也就是第九位) ;
从右向左第3位开始,第2次出现‘asdf’的索引位置
意思是说从右边的第三位开始算起,也就是从右边的第四位开始由1开始,然后第二次出现字符创的位置仍然是从左边开始的,也就是 a s d f a s d f a,但是数字就是从右边算起
9 8 7 6 5 4 3 2 1
select instr('asdfasdfasdfasdf','asdf',-3,1) from dual; --13
从右向左第3位开始,第1次出现‘asdf’的索引位置
(5)大小写的转换
select upper('asdfasgas'),lower('GHJAJDGJ') from dual;
select lower(ename),lower(job) from emp;
(6) 替换
select replace('asdfasdfasdfasdf','asdf','H') from dual;
(7) 补足字符串
select lpad('asdf',20,'*'),rpad('asdf',20,'*') from dual;
(8)去空格
select trim(' sadf ') as a,ltrim(' asdf ') as b,rtrim(' asdf ') as c from dual;
(9)去中间的空格
select replace(' asdf sdf dfasdf sdf ' , ' ' , '' ) as a from dual;
‘ 字符串 ’,分隔符 ‘ ’匹配条件 ‘’匹配结果
asdfsdfdfasdfsdf
###########################################################################################
4.数字函数
(1) 小数点后1位四舍五入
select round(2.76,1) from dual;
(2) 对整数四舍五入
select round(2.76) from dual;
(3)向上取整,ceil表示天花板
select ceil(4.3) from dual;
(4)向下取整,floor表示地板
select floor(4.8) from dual;
(5)求余数
select mod(10,3) from dual;
(6)截断
select trunc(10.454212348211,2),trunc(21154.1454211,-2) from dual;
注意:第二个参数是正数,截断小数点后面的两位
第二个参数是负数,截断小数点前面的两位
##########################################################################################
5.日期函数
(1)截断日期
select trunc(to_date('20140610','yyyy-mm-dd'),'dd'),trunc(to_date('20140610','yyyy-mm-dd'),'mm'),
trunc(to_date('20140610','yyyy-mm-dd'),'yyyy') from dual;
select trunc(to_date('20140610121212','yyyy-mm-dd hh24:mi:ss'),'hh'),
trunc(to_date('20140610121212','yyyy-mm-dd hh24:mi:ss'),'mi') from dual;
(2) 两个日期之间的天数 = 两个日期相减
select sysdate - to_date('20130610095000','yyyy-mm-dd hh24:mi:ss') from dual;
(3) 月份前后推
select add_months(sysdate,-12),add_months(sysdate,3) from dual;
第二个参数为负数,往前推
第二个参数为正数,往后推
(4) 算两个日期间隔的月数
select months_between(sysdate,to_date('20130610100000','yyyy-mm-dd hh24:mi:ss')) from dual;
例子:
计算入职时间年数的分布:
A:1年以内
B:1~3年
C:3~5年
D: 5年以上
select rs1,count(*) from
(select empno,(case when rs<=1 then 'BELOW 1'
when rs>1 and rs<3 then '1~3'
when rs>=3 and rs<5 then '3~5'
when rs>=5 then 'over 5' end) as rs1
from(
select empno,round((months_between(sysdate,hiredate)/12)) as rs
from emp
)
)group by rs1;
(5) decode函数
F=decode(p1,p2,p3,p4,p5...,pn)
含义:如果p1 = p2,F=p3
如果p1 = p4,F=p5
.....
如果都不满足,F=pn
select decode(deptno,10,'dept10',20,'dept20',30,'dept30','dept40') as x from dept;
=
select (case when deptno=10 then 'dept10'
when deptno=20 then 'dept20'
when deptno=30 then 'dept30'
else 'dept40' end
) as x
from dept;
(6)nvl函数
nvl(comm,9999) -- 如果第一个参数为null,就显示第二个参数
示例:求当第一个数为null的时候,值取9999,否则等于原值
select empno,nvl(comm,9999) as x,decode(comm,null,9999,comm) as y,(case when comm is null then 9999 else comm end) as z from emp;
###########################################################################################
6.表的连接
6.1等值连接
select b.deptno,a.ename from dept b (inner) join emp a on(a.deptno=b.deptno)
等值连接其实就是内连接
6.2左连接
select b.deptno,a.ename from dept b left (outer) join emp a on(a.deptno=b.deptno);
dept -- 主表
emp -- 副表
编写方式:主表 left join 副表,保证主表的数据不丢失
6.3右连接
select b.deptno,a.ename from emp a right join dept b on(a.deptno=b.deptno);
dept -- 主表
emp -- 副表
编写方式:副表 right join 主表,保证主表的数据不丢失
oracle语法:将左右连接统一表示
select b.deptno,a.ename from emp a, dept b where a.deptno(+)=b.deptno;
select b.deptno,a.ename from emp a, dept b where b.deptno=a.deptno(+);
(+)的对面的表就是主表
dept表是主表
emp 表是副表
注意:
A:如果副表上有过滤条件的时候,怎样满足左右连接的效果
select b.deptno,a.ename from dept b left join emp a on(a.deptno=b.deptno) where a.sal>1000;
为了加过滤条件,把主表的数据丢了,此时失去左连接的意义
select b.deptno,a.ename from dept b left join emp a on(a.deptno=b.deptno and a.sal>1000);
=
select b.deptno,a.ename from dept b,emp a where a.deptno(+)=b.deptno and a.sal(+)>1000;
B:主表上有过滤条件,不存在这个问题
数学原理:
左连接 : A∪(A∩B)
等值连接: A∩B
6.4多表关联
select * from a,b,c,d where a.x=b.x and b.y=c.y and c.z=d.z;
特殊的连接:笛卡尔积
select * from a,b
6.5非等值连接
select e.ename,s.grade,e.sal
from emp e,salgrade s
where e.sal between s.losal and s.hisal;
salgrade:薪资等级表
6.6自连接
查询所有员工的直接上司的对应关系,表示成“员工名称 work for 上司名称”,一般用在有层级关系的表上面
select worker.ename ||' work for '||manager.ename
from emp worker,emp manager
where worker.mgr=manager.empno;
##########################################################################################
7 集合运算
7.1 求差集
A. not exists操作和not in 操作
select b.deptno,b.dname,b.loc from dept b
where not exists(select a.deptno from emp a where a.deptno=b.deptno);
=
select b.deptno,b.dname,b.loc from dept b
where b.deptno not in(select a.deptno from emp a where a.deptno=b.deptno);
B. minus操作
select b.deptno from dept b
minus
select a.deptno from emp a;
7.2 求交集
A exists操作 和 in操作
select b.deptno,b.dname,b.loc from dept b
where exists(select a.deptno from emp a where a.deptno=b.deptno);
=
select b.deptno,b.dname,b.loc from dept b
where b.deptno in(select a.deptno from emp a where a.deptno=b.deptno);
B 等值连接
select distinct b.deptno,b.dname,b.loc from emp a,dept b where a.deptno=b.deptno;
7.3 求并集
A 左右连接(其中一个集合是另外一个集合的子集)
select b.deptno,a.ename from dept b left join emp a on(a.deptno=b.deptno);
B union操作
select b.deptno from dept b --合并后去重
union
select a.deptno from emp a;
select b.deptno from dept b --合并之后不去重
union all
select a.deptno from emp a;
7.4 求全集
select * from emp;
7.5 求子集
select * from emp where ename like 'T%';
7.6 求补集
select * from emp where ename not like 'T%';
7.7 求映射
select ename,job from emp where ename like 'T%';
在操作ename集合的时候,同时查询job字段映射的值
###########################################################################################
8.分组报表
select b.deptno,b.dname,nvl(floor(avg(a.sal)),0) as x,nvl(sum(a.sal),0) as y,nvl(min(a.sal),0) as z,nvl(max(a.sal),0) as l
from emp a,dept b
where a.deptno(+)=b.deptno
group by b.deptno,b.dname
order by b.deptno,b.dname;
having 字句 -- 对聚合函数的结果进行过滤
select b.deptno,b.dname,nvl(floor(avg(a.sal)),0) as x,nvl(sum(a.sal),0) as y,nvl(min(a.sal),0) as z,nvl(max(a.sal),0) as l
from emp a,dept b
where a.deptno(+)=b.deptno
group by b.deptno,b.dname
having avg(a.sal)>2000
order by b.deptno,b.dname;
注意:having字句一定要放在order by的前面,group by的后面
##########################################################################################
9.单行子查询还有多行子查询
(1) 单行子查询:返回一行的子查询
需求:显示scott员工姓名、薪水、部门号并且与其同部门的人相同信息也显示出来
select ename,sal,deptno from emp
where deptno=(select deptno from emp where ename='SCOTT')
=
select ename,sal,deptno from emp
where deptno in (select deptno from emp where ename='SCOTT')
(select deptno from emp where ename='SCOTT')返回单行,叫做单行子查询。 =、in 叫做单行操作符
(2) 多行子查询:返回多行的子查询
需求:显示部门10所有岗位job在全公司对应相同岗位人的姓名、薪水、部门号
select ename,sal,deptno from emp
where job in (select job from emp where deptno=10)
in 在这里是作为多行操作符使用
select ename,sal,deptno from emp
where job = (select job from emp where deptno=10)
错误的写法,=是单行操作符
A 在多行子查询中使用any操作符
需求:显示全公司工资高于部门10任一员工工资的员工的姓名、薪水、部门号
select ename,sal,deptno from emp
where sal > any(select sal from emp where deptno=10)
>是单行操作符,而子查询是多行的,用any来解决语法冲突,满足'任一'这种需求
B 在多行子查询中使用all操作符
需求:显示全公司工资高于部门20所有员工工资的员工的姓名,薪水,部门号
select ename,sal,deptno from emp where sal > all(select sal from emp where deptno=20)
>是单行操作符,而子查询是多行的,用all来解决语法冲突,满足'所有'这种需求
注意:
1.子查询中不能写order by
2.多行子查询不能用单行操作符匹配
3.单行子查询可以匹配多行操作符
4.子查询必须写在括号里面
5.子查询要放在比较运算符后面
10. 嵌套子查询(多个子查询)
select ename,sal,deptno from emp
where sal > (select sal from emp where empno=7876) and job = (select job from emp where empno=7369);