oracle两表子查询,Oracle多表查询、子查询实战练习

一、基础练习:

1.查询和scott相同部门的员工姓名ename和雇用日期hiredate

SELECT ENAME,HIREDATE FROM EMP WHERE DEPTNO=(SELECT DEPTNO FROM EMP WHERE ENAME='SCOTT');

f2a68b8740a8666a12bbd0c47c14550b.png

2.查询在部门的loc为NEW YORK的部门工作的员工的员工姓名ename,部门名称dname和岗位名称job

SELECT E.ENAME,D.DNAME,E.JOB,D.LOC FROM EMP E,DEPT D WHERE E.DEPTNO=D.DEPTNO AND D.LOC='NEW YORK';

d4a853563d63e015c22d5bb91a07225a.png

3.查询上司是king的员工姓名(ename)和工资(sal)

SELECT ENAME,SAL FROM EMP WHERE MGR=(SELECT EMPNO FROM EMP WHERE ENAME='KING');

00644196c86a18609eaef0eae327d9a3.png

4.查询与姓名中包含字母U的员工在相同部门的员工信息

SELECT * FROM EMP WHERE DEPTNO IN(SELECT DEPTNO FROM EMP WHERE ENAME LIKE '%U%');

a339caea9f19c6dee5a266e859f76609.png

5.查询所有雇员姓名和部门名称(使用left join,inner join, right join)

SELECT E.ENAME,D.DNAME FROM EMP E INNER JOIN DEPT D ON E.DEPTNO=D.DEPTNO;

SELECT E.ENAME,D.DNAME FROM EMP E LEFT JOIN DEPT D ON E.DEPTNO=D.DEPTNO;

SELECT E.ENAME,D.DNAME FROM DEPT D RIGHT JOIN EMP E ON E.DEPTNO=D.DEPTNO;

06e087c67f7ea6e1aada24490b17e2cf.png

6.显示每个员工的员工姓名、部门名称、职务、工资、和工资等级信息(使用left join,inner join, right join)

SELECT E.ENAME,D.DNAME,E.JOB,E.SAL,S.GRADE FROM EMP E INNER JOIN DEPT D ON E.DEPTNO=D.DEPTNO INNER JOIN SALGRADE S ON E.SAL BETWEEN S.LOSAL AND S.HISAL;

SELECT E.ENAME,D.DNAME,E.JOB,E.SAL,S.GRADE FROM EMP E LEFT JOIN DEPT D ON E.DEPTNO=D.DEPTNO LEFT JOIN SALGRADE S ON E.SAL BETWEEN S.LOSAL AND S.HISAL;

SELECT E.ENAME,D.DNAME,E.JOB,E.SAL,S.GRADE FROM DEPT D RIGHT JOIN EMP E ON E.DEPTNO=D.DEPTNO RIGHT JOIN SALGRADE S ON E.SAL BETWEEN S.LOSAL AND S.HISAL;

3c3d759ee05a6ad58fd14110cce0f4b5.png

二、综合练习

1.取得每个部门最高薪水的人员名称2.列出受雇日期早于其直接上级的所有员工的编号,姓名,部门名称

--使用相关子查询

SELECT EMPNO,ENAME,SAL,DEPTNO FROM EMP E WHERE E.SAL=(SELECT MAX(SAL) FROM EMP M WHERE M.DEPTNO=E.DEPTNO) ORDER BY DEPTNO;

--使用多表连接查询(渔舟唱晚同学的)

SELECT EMPNO,ENAME,SAL,DEPTNO FROM EMP Q, (SELECT E.DEPTNO 部门, MAX(E.SAL) 最高薪资 FROM EMP E GROUP BY E.DEPTNO)

R WHERE R.部门 = Q.DEPTNO AND Q.SAL = R.最高薪资 ORDER BY Q.DEPTNO;

--使用DENSE_RANK()函数结合ORDER BY

SELECT * FROM(SELECT EMPNO,ENAME,SAL,DEPTNO,DENSE_RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC)RN FROM EMP) WHERE RN=1 ORDER BY DEPTNO;

--使用IN子查询(有BUG)

SELECT EMPNO,ENAME,DEPTNO,SAL FROM EMP WHERE SAL IN(SELECT MAX(SAL) FROM EMP GROUP BY DEPTNO) ORDER BY DEPTNO;

a3089bdedd03c3c2ceb2f9c189208405.png

--测试上面的IN子查询BUG:发现10部门的NulluN也显示出来了,但其并非10部门最高工资,10部门最高工资为5000

INSERT INTO EMP(EMPNO,ENAME,DEPTNO,SAL) VALUES(1015,'NulluN',10,3000);

SELECT EMPNO,ENAME,DEPTNO,SAL FROM EMP WHERE SAL IN(SELECT MAX(SAL) FROM EMP GROUP BY DEPTNO) ORDER BY DEPTNO;

ef2fbae6f14f263cba7220f7e3e5dee8.png

2.列出受雇日期早于其直接上级的所有员工的编号,姓名,部门名称

--左自连接和多表查询

SELECT E.EMPNO 员工编号,E.ENAME 员工姓名,M.ENAME 主管姓名,E.HIREDATE 员工受雇日期, M.HIREDATE 上级雇用日期,D.DNAME 部门名称

FROM EMP E,EMP M,DEPT D WHERE M.EMPNO(+)=E.MGR AND E.HIREDATE

4801f1b401d180d08d777e3bb83cce02.png

--相关子查询和多表查询

SELECT E.EMPNO,E.ENAME,D.DNAME FROM EMP E,DEPT D WHERE E.HIREDATE

80ffb3b781b944ce1d880c8c860ed932.png

3.列出所有"CLERK"(办事员)的姓名及其部门名称,部门的人数

思路:1.先查询JOB为CLERK的所有部门编号,将该子查询结果命名为A;2.再从EMP表查询与A查询中部门编号相同的员工所在的部门人数,这一步的查询结果命名为B;3.最后从EMP表、DEPT表和B查询中进行多表查询获取JOB为CLERK的所有员工的姓名、部门名称和所在部门人数。

SELECT E.ENAME,D.DNAME,T.部门人数,E.JOB FROM EMP E,DEPT D,(SELECT DEPTNO,COUNT(1) 部门人数 FROM EMP WHERE DEPTNO IN(

SELECT DISTINCT DEPTNO FROM EMP WHERE JOB='CLERK') GROUP BY DEPTNO)T

WHERE E.DEPTNO=D.DEPTNO AND E.JOB='CLERK' AND T.DEPTNO=E.DEPTNO;

df955c524b5a1e09cdaefa80eb63e39c.png

4.列出与"SCOTT"从事相同工作的所有员工及部门名称

SELECT E.*,D.DNAME FROM EMP E,DEPT D WHERE E.JOB=(SELECT JOB FROM EMP WHERE ENAME='SCOTT') AND E.DEPTNO=D.DEPTNO;

d4ecd397149f7a59f22a01d5b70bf626.png

5.查出某个员工的上级主管,并要求出这些主管中的薪水超过3000

SELECT E.EMPNO 员工编号,E.ENAME 员工姓名,M.ENAME 主管姓名,M.SAL 主管工资 FROM EMP E,EMP M WHERE M.EMPNO(+)=E.MGR AND M.SAL>3000;

81b9f1c5d968b73f236ad8f66ac7083f.png

6.找出部门10中所有经理(MANAGER)和部门20中所有办事员(CLERK)的详细资料

SELECT E.*,D.DNAME,D.LOC,S.* FROM EMP E,DEPT D,SALGRADE S WHERE E.DEPTNO=D.DEPTNO AND E.SAL BETWEEN S.LOSAL AND S.HISAL

AND (E.DEPTNO=10 AND E.JOB='MANAGER' OR E.DEPTNO=20 AND E.JOB='CLERK');

--注意:E.DEPTNO=10 AND E.JOB='MANAGER' OR E.DEPTNO=20 AND E.JOB='CLERK' 要用括号括起来,不然会与前面的AND条件混淆造成错误!

1262cd8c3905b7673b1eb08d5b572b17.png

7.找出早于12年前受雇的员工. 并且按受雇年份倒序排序

思路一:用MONTHS_BETWEEN比较当前系统时间和受雇日期之前相差的月份,然后除以12,如果值大于12,则是早于12前受雇的员工。

--有错误的语句

SELECT E.*,TO_CHAR(HIREDATE,'YYYY') 受雇年份,ROUND((MONTHS_BETWEEN(SYSDATE,HIREDATE)/12),2) 受雇年限 FROM EMP E WHERE 受雇年限>12 ORDER BY 受雇年份 DESC;

/*为什么“受雇年限”会是无效的标识符呢?因为SELECT语句在WHERE语句后面才执行,而列的别名(受雇年限)是在SELECT时才生成的,故在WHERE子句中看不到这个别名(受雇年限),自然无法引用这个别名了。*/--排错后的正确语句

SELECT E.*,TO_CHAR(HIREDATE,'YYYY') 受雇年份,ROUND((MONTHS_BETWEEN(SYSDATE,HIREDATE)/12),2) 受雇年限 FROM EMP E WHERE (MONTHS_BETWEEN(SYSDATE,HIREDATE)/12)>12 ORDER BY 受雇年份 DESC;

76a3e9396911296451c833c9da3355c0.png

思路二:用ADD_MONTHS判断,(受雇日期+12*12)得出的日期如果小于当前系统时间,则是早于12前受雇的员工。

SELECT E.*,TO_CHAR(HIREDATE,'YYYY') 受雇年份,ADD_MONTHS(HIREDATE,12*12) 受雇十二周年日,ROUND((MONTHS_BETWEEN(SYSDATE,HIREDATE)/12),2) 受雇年限 FROM EMP E

WHERE ADD_MONTHS(HIREDATE,12*12)

--注意:离当前日期越远的日期越小,反之,离当前日期越近的日期越大。

3392719cc69080143f5d14e9f360db0c.png

8.列出从事同一种工作但属于不同部门的员工的一种组合

--不算完美但算比较接近题意的SQL语句

SELECT DISTINCT E.EMPNO,E.ENAME,E.JOB,E.DEPTNO FROM EMP E,EMP P WHERE E.DEPTNO!=P.DEPTNO AND E.JOB=P.JOB ORDER BY JOB,DEPTNO;

--其它两种不等于的写法

SELECT DISTINCT E.EMPNO,E.ENAME,E.JOB,E.DEPTNO FROM EMP E,EMP P WHERE E.DEPTNO<>P.DEPTNO AND E.JOB=P.JOB ORDER BY JOB,DEPTNO;

SELECT DISTINCT E.EMPNO,E.ENAME,E.JOB,E.DEPTNO FROM EMP E,EMP P WHERE E.DEPTNO^=P.DEPTNO AND E.JOB=P.JOB ORDER BY JOB,DEPTNO;

/*精妙之处:使用DISTINCT!如果不使用DISTINCT,查询结果会出现很多一样的重复数据!*/

9aacbe649b91dfc53729a0ed1b3d4ab8.png

分析:为什么说上面的SQL语句不算完美呢?因为从上图可看出JOB为CLERK,且DEPTNO=20的记录有两条,即分别是第2和第3条查询记录,这就与题目要求的“从事同一种工作但属于不同部门的员工”不一致了,故最理想的查询结果应该如下:

c6a58c60b92bd763419f7c6a33841023.png   

252a5a752e423a71a1501177c613d743.png

9.查询有奖金的所有员工的姓名、奖金以及所在部门名称

--如果奖金等于0也算有奖金,那如下实现:

SELECT ENAME,COMM,DNAME FROM EMP E,DEPT D WHERE COMM IS NOT NULL AND E.DEPTNO=D.DEPTNO;

ab27da6bf19a4f8fcfdb8125744b071d.png

--如果奖金等于0不算有奖金,则如下实现:

SELECT ENAME,COMM,DNAME FROM EMP E,DEPT D WHERE COMM IS NOT NULL AND COMM<>0 AND E.DEPTNO=D.DEPTNO;

f3eddc1b0fbf084d6d865ed20896acfb.png

10.给任职日期超过25年的员工加薪10%

SELECT E.ENAME,E.SAL 原薪水,E.SAL*1.1 加薪后薪水,ROUND((MONTHS_BETWEEN(SYSDATE,HIREDATE)/12),2) 受雇年限 FROM EMP E

WHERE (MONTHS_BETWEEN(SYSDATE,HIREDATE)/12)>25;

bce032eafeefe75d3b11b72549f06f4e.png

0b1331709591d260c1c78e86d0c51c18.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值