1.一个新的要求:要求查询出雇员的编号,姓名,工作,但是显示的格式:
编号是:7369的雇员,姓名是:SMITH,工作是:CLERK
要想实现此种功能,则可以使用Oracle中提供的字符串连接操作,使用“||”表示。如果要加入一些显示信息的话,所有的其他的固定信息要使用“'”括起来。
SELECT '编号是:' || empno || '的雇员,姓名是:' || ename || ',工作是:' || job
FROM emp ;
2.要求两个条件全部满足,则必须使用AND操作符进行条件的连接。
SELECT * FROM emp WHERE sal>1500 AND comm IS NOT NULL ;
3.要表现出或者的概念使用OR进行连接,表示两个条件有一个满足即可。
SELECT * FROM emp WHERE sal>1500 OR comm IS NOT NULL ;
4.NOT可以取反,把真的条件变为假的,假的变为真的。
范例:要求查询出,基本工资不大于1500,同时不可以领取奖金的雇员信息。此时相当于是整体的条件取反。
SELECT * FROM emp WHERE NOT (sal>1500 AND comm IS NOT NULL) ;
5.sal BETWEEN 1500 AND 3000 操作等价:sal>=1500 AND sal<=3000,包含等于的功能。
BETWEEN … AND查询除了可以支持数字之外,也可以支持日期的查询
6.IN的使用:
语法格式: 字段 IN (值1,值2,…..,值n)
如果现在要求查询的内容不在此范围之中,则可以使用NOT IN,语法如下:
字段 NOT IN (值1,值2,…..,值n)
7.LIKE:在LIKE语句中主要使用以下两种通配符:
“%”:可以匹配任意长度的内容
“_”:可以匹配一个长度的内容
8.不等于符号:在SQL中如果要想使用不等于符号,可以有两种形式:“<>”、“!=”
9.oeder by 字段名 升序ASC or 降序DESC
范例:要求查询出10部门的所有雇员信息,查询的信息按照工资由高到低排序,如果工资相等,则按照
雇佣日期由早到晚排序。
· 此时存在两个排序条件,第一个是降序,第二个升序
SELECT * FROM emp
WHERE deptno=10
ORDER BY sal DESC,hiredate ASC ;
注意:排序的操作肯定是放在整个SQL语句的最后执行。
10.字符函数:UPPER() LOWER()
select UPPER('hehe') from dual;
SELECT * FROM emp WHERE ename=UPPER('Smith') ;
SELECT LOWER('HELLO WORLD') FROM dual ;
initcap()函数将单词的第一个字母大写
SELECT INITCAP('HELLO WORLD') FROM dual ;
字符串除了可以使用“||”连接之外,还可以使用CONCAT()函数进行连接操作。
SELECT CONCAT('hello ','world') FROM DUAL ;
· 字符串截取:substr()
· 字符串长度:length()
· 内容替换:replace()
SELECT substr('hello',1,3) 截取字符串 ,
length('hello') 字符串长度 ,
replace('hello','l','x') 字符串替换
FROM DUAL ;
范例:要求显示所有雇员的姓名及姓名的后三个字符
SELECT ename,SUBSTR(ename,-3,3) FROM emp ;
11.数值函数
· 四舍五入:ROUND()
范例:保留两位小数
SELECT ROUND(789.536,2) FROM dual ;
· 截断小数位:TRUNC()
在TRUNC()操作中,不会保留任何的小数,而且小数点也不会执行四舍五入的操作。
· 取余(取模):MOD
范例:使用MOD()函数可以进行取余的操作
SELECT MOD(10,3) FROM DUAL ;
12.日期函数
· 日期 – 数字 = 日期
· 日期 + 数字 = 日期
· 日期 – 日期 = 数字(天数)
· 求出星期数:当前日期 – 雇佣日期 = 天数 / 7 = 星期数
SELECT empno,ename,ROUND((SYSDATE-hiredate)/7) FROM emp ;
在Oracle中提供了以下的日期函数支持:
· MONTHS_BETWEEN():求出给定日期范围的月数
· ADD_MONTHS():在指定日期上加上指定的月数,求出之后的日期
· NEXT_DAY():下一个的今天是那一个日期
· LAST_DAY():求出给定日期的最后一天日期
13.转换函数主要有以下几种:
· TO_CHAR():转换成字符串
SELECT empno,ename,TO_CHAR(hiredate,'yyyy') year ,
TO_CHAR(hiredate,'mm') months ,
TO_CHAR(hiredate,'dd') day
FROM emp ;
SELECT empno,ename,TO_CHAR(hiredate,'fmyyyy-mm-dd') FROM emp ;
SELECT empno,ename,TO_CHAR(sal,'$99,999') FROM emp ;
· TO_NUMBER():转换成数字
SELECT TO_NUMBER('123') + TO_NUMBER('123') FROM DUAL ;
· TO_DATE():转换成日期
SELECT TO_DATE('2009-02-16','yyyy-mm-dd') FROM DUAL ;
14.通用函数
范例:要求求出每个雇员的年薪
· 求出年薪的时候应该加上奖金的,格式(sal+comm)*12
SELECT empno,ename,NVL(comm,0),(sal+NVL(comm,0))*12 income
FROM emp ;
DECODE()函数,此函数是在面试最有可能问到的问题。DECODE()类似于IF…ELSEIF…ELSE语句。
语法:
DECODE(col/expression,search1,result1[,search2,result2,...][,default])
说明:
col/expression:为列名或表达式
search1、search2…searchi:为用于比较的条件
result1、result2…resulti为返回值
如果col/expression和searchi相比较,结果相同的话,则返回resulti,如果没有与col/expression相匹配的结果,则返回默认枝default。\
范例:验证DECODE()函数
SELECT DECODE(1,1,'内容是1',2,'内容是2',3,'内容是3')
FROM DUAL ;
范例:要求查询出雇员的编号,姓名,雇佣日期及工作,将工作替换成以上的信息
SELECT empno 雇员编号 ,ename 雇员姓名 ,hiredate 雇佣日期 ,
DECODE(job,'CLERK','业务员','SALESMAN','销售人员','MANAGER','经理','ANALYST','分析员','PRESIDENT','总裁') 职位
FROM emp ;
15.练习:
1、选择部门30中的所有员工。
SELECT * FROM emp WHERE deptno=30 ;
2、列出所有办事员(CLERK)的姓名,编号和部门编号。在Oracle中是区分大小写的,所以此时要么将CLERK大写,要么使用upper函数
SELECT ename,empno,deptno FROM emp WHERE job=UPPER('clerk') ;
3、找出佣金高于薪金的员工。· comm字段表示佣金或奖金,comm>sal
SELECT * FROM emp WHERE comm>sal ;
4、找出佣金高于薪金的60%的员工。
SELECT * FROM emp WHERE comm>sal*0.6 ;
5、找出部门10中所有经理(MANAGER)和部门20中所有办事员(CLERK)的详细资料。
SELECT * FROM emp
WHERE (deptno=10 AND job='MANAGER') OR (deptno=20 AND job='CLERK') ;
6、找出部门10中所有经理(MANAGER),部门20中所有办事员(CLERK),既不是经理又不是办事员但其薪金大于或等于2000的所有员工的详细资料。
SELECT * FROM emp
WHERE (deptno=10 AND job='MANAGER')
OR (deptno=20 AND job='CLERK')
OR (job NOT IN('MANAGER','CLERK') AND sal>=2000);
7.收到佣金的员工的不同工作 · 工作会出现重复,所以DISTIN
· comm. IS NOT NULL
SELECT DISTINCT job FR WHERE comm IS NOT NULL ;
8、找出不收取佣金或收取的佣金低于100的员工。· comm. IS NULL OR comm.<100
SELECT * FROM emp WHERE comm IS NULL OR comm<100 ;
9、找出各月倒数第3天受雇的所有员工。· 要使用LAST_DAY()函数进行处理:LAST_DAY(hiredate)-2=hiredate
SELECT * FROM emp WHERE LAST_DAY(hiredate)-2=hiredate ;
10、找出早于12年前受雇的员工。 · 条件:MONTHS_BETWEE() / 12,求出总共的月再除以12
SELECT * FROM emp WHERE MONTHS_BETWEEN(sysdate,hiredate) / 12 > 12 ;
11、以首字母大写的方式显示所有员工的姓名。· initcap()函数
SELECT INITCAP(ename) FROM emp ;
12、显示正好为5个字符的员工的姓名。 · length()函数
SELECT ename FROM emp WHERE LENGTH(ename)=5 ;
13、显示不带有“R”的员工的姓名。 · NOT LIKE
SELECT ename FROM emp WHERE ename NOT LIKE '%R%' ;
14、显示所有员工姓名的前三个字符。· substr()字符串截取
SELECT SUBSTR(ename,0,3) FROM emp ;
15、显示所有员工的姓名,用“a”替换所有“A”· replace()函数
SELECT REPLACE(ename,'A','a') FROM emp ;
16、显示满10年服务年限的员工的姓名和受雇日期。
SELECT ename,hiredate FROM emp
WHERE MONTHS_BETWEEN(sysdate,hiredate) / 12 > 10 ;
17、显示员工的姓名和受雇日期,根据其服务年限,将最老的员工排在最前面。 · ORDER BY,进行排序操作
SELECT * FROM emp ORDER BY hiredate ;
18、显示所有员工的姓名、工作和薪金,按工作的降序排序,若工作相同则按薪金排序。
SELECT ename,job,sal FROM emp ORDER BY job DESC,sal ;
19、显示所有员工的姓名、加入公司的年份和月份,按受雇日期所在月排序,若月份相同则将最早年份的员工排在最前面。
· 要先求出所有员工的雇佣月份 · to_char()函数求出月
SELECT ename,TO_CHAR(hiredate,'yyyy') year, TO_CHAR(hiredate,'mm') mon FROM emp
ORDER BY mon,year ;
20、显示在一个月为30天的情况所有员工的日薪金,忽略余数· 忽略余数;使用ROUND()函数完成
SELECT ename,ROUND(sal/30) FROM emp ;
21、找出在(任何年份的)2月受聘的所有员工。· 还是使用 to_char()函数,求出月
SELECT * FROM emp WHERE TO_CHAR(hiredate,'mm')=2 ;
22、对于每个员工,显示其加入公司的天数。
· 日期- 日期 = 天数
SELECT ename,ROUND(SYSDATE-hiredate) FROM emp ;
23、显示姓名字段的任何位置包含“A”的所有员工的姓名.
SELECT * FROM emp WHERE ename LIKE '%A%' ;
24、以年月日的方式显示所有员工的服务年限。(大概) · 年:求出总共的月 / 12 ?? 会产生小数,但是不应该四舍五入
SELECT ename,TRUNC(MONTHS_BETWEEN(sysdate,hiredate)/12) year FROM emp ;
25.SELECT ename,TRUNC(MONTHS_BETWEEN(sysdate,hiredate)/12) year ,
TRUNC(MOD(MONTHS_BETWEEN(sysdate,hiredate),12)) mon
FROM emp ;
26.SELECT ename,TRUNC(MONTHS_BETWEEN(sysdate,hiredate)/12) year ,
TRUNC(MOD(MONTHS_BETWEEN(sysdate,hiredate),12)) mon ,
TRUNC(MOD(sysdate-hiredate,30)) day
FROM emp ;
多表查询:
1.范例:要求查询出雇员的编号、雇员的姓名、部门的编号、部门名称及部门位置
SELECT e.empno,e.ename,d.deptno,d.dname,d.loc
FROM emp e,dept d
WHERE e.deptno=d.deptno ;
2.自连接:
范例:要求查询出每个雇员的姓名、工作、雇员的直接上级领导的姓名在emp表中的mgr字段使用没有使用过,其表示一个雇员的上级领导的编号。那么如果现在要想查询一个雇员的上级领导,则肯定要将emp表与emp表自己进行关联。
SELECT e.ename,e.job,m.ename
FROM emp e,emp m
WHERE e.mgr=m.empno ;
范例:要求进一步扩展之前的程序,将雇员所在的部门名称同时列出 · 部门名称在dept表中存在定义。
SELECT e.ename,e.job,m.ename,d.dname
FROM emp e,emp m,dept d
WHERE e.mgr=m.empno AND e.deptno=d.deptno ;
现在要求查询出每个雇员的姓名、工资,部门名称,工资等级领导姓名及工资所在公司的等级。
SELECT e.ename,e.sal,d.dname,
DECODE(s.grade,1,'第五等工资',2,'第四等工资',3,'第三等工资'
,4,'第二等工资',5,'第一等工资'),m.ename,m.sal,
DECODE(ms.grade,1,'第五等工资',2,'第四等工资',3,'第三等工资'
,4,'第二等工资',5,'第一等工资')
FROM emp e,dept d,salgrade s,emp m,salgrade ms
WHERE e.deptno=d.deptno AND
e.sal BETWEEN s.losal AND s.hisal AND e.mgr=m.empno
AND m.sal BETWEEN ms.losal AND ms.hisal;
3.· (+)在=左边表示右连接 左边为空
· (+)在=右边表示左连接 右边为空
SELECT e.empno,e.ename,m.empno,m.ename
FROM emp e,emp m
WHERE e.mgr=m.empno(+) ; 右边显示为空
4.SQL1999
范例:交叉连接(CROSS JOIN):产生笛卡尔积
SELECT * FROM emp CROSS JOIN dept ;
范例:自然连接(NATURAL JOIN):自动进行关联字段的匹配
SELECT * FROM emp NATURAL JOIN dept ;
范例:USING子句:直接关联的操作列
SELECT * FROM emp e JOIN dept d USING(deptno)
WHERE deptno=30 ;
范例:ON子句,用户自己编写连接的条件
SELECT * FROM emp e JOIN dept d ON(e.deptno=d.deptno)
WHERE deptno=30 ;
范例:左连接(左外连接)、右连接(右外连接):LEFT JOIN,RIGHT JOIN
SELECT e.ename,d.deptno,d.dname,d.loc
FROM emp e RIGHT OUTER JOIN dept d
ON(e.deptno=d.deptno) ;
5.组函数和分组统计
· COUNT():求出全部的记录数
· MAX():求出一组中的最大值
· MIN():求出最小值
· AVG():求出平均值
· SUM():求和
注意:在使用分组函数的时候,不能出现分组函数和分组条件之外的字段。
SELECT deptno,empno,COUNT(empno)
FROM emp
GROUP BY deptno ;(错误使用)
范例:按部门分组,并显示部门的名称,及每个部门的员工数
SELECT d.dname,COUNT(e.empno)
FROM dept d,emp e
WHERE d.deptno=e.deptno
GROUP BY d.dname ;
范例:使用HAVING完成以上的操作
SELECT deptno,AVG(sal)
FROM emp
GROUP BY deptno HAVING AVG(sal)>2000 ;
范例:显示非销售人员工作名称以及从事同一工作雇员的月工资的总和,并且要满足从事同一工作的雇员的月工资合计大于$5000,输出结果按月工资的合计升序排列
SELECT job,SUM(sal) su
FROM emp
WHERE job<>'SALESMAN'
GROUP BY job HAVING SUM(sal)>5000
ORDER BY su ;
子查询:
*********************************************************
子查询在操作中有分为以下三类:
· 单列子查询:返回的结果是一列的一个内容,出现几率最高
· 单行子查询:返回多个列,有可能是一条完整的记录
· 多行子查询:返回多条记录
*********************************************************
要求查询出:部门名称、部门的员工数,部门的平均工资,部门的最低收入雇员的姓名
程序需要两张表关联:dept、emp
SELECT d.dname,ed.c,ed.a,e.ename
FROM dept d,(
SELECT deptno,COUNT(empno) c,AVG(sal) a,MIN(sal) min
FROM emp
GROUP BY deptno) ed,emp e
WHERE d.deptno=ed.deptno AND e.sal=ed.min ;
范例:求出每个部门的最低工资的雇员信息· 每个部门的最低工资,返回的值肯定是多个,所以此时可以使用IN指定一个操作的范围。
SELECT * FROM emp
WHERE sal IN (SELECT MIN(sal) FROM emp GROUP BY deptno) ;
ANY操作:· =ANY:与IN的操作符功能完全一样
SELECT * FROM emp
WHERE sal =ANY (SELECT MIN(sal) FROM emp GROUP BY deptno) ;
· >ANY:比里面最小的值要大
SELECT * FROM emp
WHERE sal >ANY (SELECT MIN(sal) FROM emp GROUP BY deptno) ;
· <ANY:比最大的值要小
SELECT * FROM emp
WHERE sal <ANY (SELECT MIN(sal) FROM emp GROUP BY deptno) ;
ALL操作:
· >ALL:比最大的值要大
SELECT * FROM emp
WHERE sal >ALL (SELECT MIN(sal) FROM emp GROUP BY deptno) ;
· <ALL:比最小的值要小
SELECT * FROM emp
WHERE sal <ALL (SELECT MIN(sal) FROM emp GROUP BY deptno) ;
1、列出至少有一个员工的所有部门。
SELECT d.*,ed.cou
FROM dept d,(SELECT deptno,COUNT(empno) cou FROM emp
GROUP BY deptno HAVING COUNT(empno)>1) ed
WHERE d.deptno=ed.deptno ;
2、列出薪金比“SMITH”多的所有员工。
SELECT * FROM emp
WHERE sal>(SELECT sal FROM emp WHERE ename='SMITH') ;
3、列出所有员工的姓名及其直接上级的姓名。
· 此程序属于自身关联查询
SELECT e.ename,m.ename
FROM emp e,emp m
WHERE e.mgr=m.empno ;
4、列出受雇日期早于其直接上级的所有员工的编号,姓名,部门名称。
· 自身关联,查找mgr=empno的同时还要比较hiredate,先查询编号、姓名
SELECT e.empno,e.ename
FROM emp e,emp m
WHERE e.mgr=m.empno AND e.hiredate<m.hiredate ;
· 如果要加入部门的名称,则肯定应该加入dept表,做表关联查询
SELECT e.empno,e.ename,d.dname
FROM emp e,emp m,dept d
WHERE e.mgr=m.empno AND e.hiredate<m.hiredate AND e.deptno=d.deptno ;
5、列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门。
· 左、右关联问题
SELECT d.deptno,d.dname,e.empno,e.ename
FROM dept d,emp e
WHERE d.deptno=e.deptno(+) ;
6、列出所有“CLERK”(办事员)的姓名及其部门名称,部门的人数。
SELECT e.ename,d.dname,ed.cou
FROM emp e,dept d,(SELECT deptno,COUNT(empno) cou FROM emp GROUP BY deptno) ed
WHERE job='CLERK' AND e.deptno=d.deptno AND ed.deptno=e.deptno ;
7、列出最低薪金大于1500的各种工作及此从事此工作的全部雇员人数。
SELECT e.job,COUNT(e.empno)
FROM emp e
WHERE e.job IN(
SELECT job
FROM emp
GROUP BY job HAVING MIN(sal)>1500)
GROUP BY e.job ;
8、列出在部门“SALES”(销售部)工作的员工的姓名,假定不知道销售部的部门编号。
SELECT ename
FROM emp WHERE deptno=(
SELECT deptno FROM dept WHERE dname='SALES') ;
9、列出薪金高于公司平均薪金的所有员工,所在部门,上级领导,公司的工资等级。
SELECT e.empno,e.ename,s.grade,m.empno,m.ename,d.deptno,d.dname,d.loc
FROM emp e,dept d,emp m,salgrade s
WHERE e.sal>(SELECT AVG(sal) FROM emp)
AND e.deptno=d.deptno
AND e.mgr=m.empno(+)
AND e.sal BETWEEN s.losal AND s.hisal;
10、列出与“SCOTT”从事相同工作的所有员工及部门名称。
SELECT e.empno,e.ename,e.job,e.sal,d.dname,d.loc
FROM emp e,dept d
WHERE job=(SELECT job FROM emp WHERE ename='SCOTT')
AND ename!='SCOTT'
AND e.deptno=d.deptno ;
11、列出薪金等于部门30中员工的薪金的所有员工的姓名和薪金。
SELECT ename,sal
FROM emp WHERE sal IN (
SELECT sal FROM emp WHERE deptno=30)
AND deptno!=30 ;
12、列出薪金高于在部门30工作的所有员工的薪金的员工姓名和薪金、部门名称。
SELECT e.ename,e.sal,d.dname,d.loc
FROM emp e,dept d
WHERE e.sal >ALL (
SELECT sal FROM emp WHERE deptno=30)
AND e.deptno!=30 AND e.deptno=d.deptno ;
13、列出在每个部门工作的员工数量、平均工资和平均服务期限。
· 每个部门工作的员工数量:求的时候可以求出部门名称
SELECT d.dname,COUNT(e.empno)
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY d.dname ;
SELECT d.dname,COUNT(e.empno),AVG(e.sal),
AVG(MONTHS_BETWEEN(sysdate,e.hiredate)/12) 年
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY d.dname ;
14、列出所有员工的姓名、部门名称和工资。
· 直接两张表关联
SELECT e.ename,d.dname,e.sal
FROM emp e,dept d
WHERE e.deptno=d.deptno ;
15、列出所有部门的详细信息和部门人数。
SELECT d.*,NVL(ed.cou,0)
FROM dept d,(SELECT deptno dno,COUNT(empno) cou FROM emp GROUP BY deptno) ed
WHERE d.deptno=ed.dno(+) ;
16、列出各种工作的最低工资及从事此工作的雇员姓名。
SELECT * FROM emp
WHERE sal IN (SELECT MIN(sal) FROM emp GROUP BY job) ;
17、列出各个部门的MANAGER(经理)的最低薪金。
SELECT deptno,MIN(sal)
FROM emp
WHERE job='MANAGER'
GROUP BY deptno ;
18、列出所有员工的年工资,按年薪从低到高排序。
· 在处理年薪的时候需要注意奖金,奖金要使用NVL函数处理
SELECT ename,(sal+NVL(comm,0)) * 12 income
FROM emp
ORDER BY income;
19、查出某个员工的上级主管,并要求出这些主管中的薪水超过3000
SELECT DISTINCT m.*
FROM emp e,emp m
WHERE e.mgr=m.empno AND m.sal>3000 ;
20、求出部门名称中,带‘S’字符的部门员工的、工资合计、部门人数
SELECT deptno,SUM(sal),COUNT(empno)
FROM emp
WHERE deptno IN (SELECT deptno FROM dept WHERE dname LIKE '%S%')
GROUP BY deptno ;
21、给任职日期超过10年的人加薪10%
UPDATE emp SET sal=sal + (sal*0.1)
WHERE MONTHS_BETWEEN(sysdate,hiredate)/12>10 ;