多表查询-子查询-分页查询
day_02
-.多表查询
SELECT 列名,列名...
FROM 表名 表的别名,表名 表的别名...
WHERE 条件
ORDER BY 排序字段...
1.笛卡尔积:是多张表记录的乘积
SELECT *
FROM emp,dept
wherer ename='SMITH';
SELECT * FROM emp;
SELECT * FROM dept;
SELECT ename,emp.deptno,dname
FROM emp,dept;
2.等值连接,两张表中存在含义相同,值相等的列
起别名后原名不在生效,别名生效
SELECT *
FROM emp ,dept
WHERE emp.deptno=dept.deptno;
3.不等值连接
SELECT * FROM salgrade;
SELECT *
FROM emp a,salgrade b
--WHERE a.sal>=b.losal AND a.sal<=b.hisal;
WHERE sal BETWEEN losal AND hisal;
--查询员工的姓名,员工的部门名称,员工的工资等级
SELECT ename,dname,grade
FROM emp,dept,salgrade
WHERE emp.deptno=dept.deptno AND sal BETWEEN losal AND hisal;
4.自身连接
SELECT * FROM emp;
SELECT *
FROM emp a,emp b
WHERE a.mgr=b.empno;
--查询员工的姓名,员工的部门名称,员工的工资等级,
--员工对应的领导的姓名,领导的部门,领导的工资等级
SELECT e.ename 员工姓名,d.dname 员工部门,s.grade 员工工资等级 ,
m.ename 领导姓名,md.dname 领导部门,ms.grade 领导工资等级
FROM emp e,emp m,dept d,salgrade s,dept md,salgrade ms
WHERE e.deptno=d.deptno AND e.sal BETWEEN s.losal AND s.hisal AND
e.mgr=m.empno AND m.deptno=md.deptno AND
m.sal BETWEEN ms.losal AND ms.hisal;
5.外连接
SELECT *
FROM emp,dept
WHERE emp.deptno(+)=dept.deptno; --右连接
SELECT *
FROM emp,dept
WHERE dept.deptno=emp.deptno(+);--左连接
6.sql1999:
(01)CROSS JOIN:交叉连接,笛卡尔积
语法:tabel1 CROSS JOIN tabel2
SELECT * FROM emp CROSS JOIN dept;
=
SELECT * FROM emp,dept;
(02)NATURAL JOIN:自然连接
语法:tabel1 NATURAL JOIN tabel2
SELECT *
FROM emp NATURAL JOIN dept;
(03)join...using(公共列名) 2和3都是公共列在前
语法:TABLE JOIN table2 USING(公共列)
SELECT *
FROM emp JOIN dept USING(deptno);
(04)join...on 连接条件
语法:tabel1 JOIN table2 ON 连接条件
SELECT *
FROM emp JOIN dept ON emp.deptno=dept.deptno;
(05)LEFT JOIN ...on 连接条件 左连接左不为空
语法:table1 LEFT JOIN table2 ON 连接条件
SELECT *
FROM dept LEFT JOIN emp ON emp.deptno=dept.deptno;
(06)RIGHT JOIN ...on 连接条件 右连接右不为空
语法:table1 RIGHT JOIN table2 ON 连接条件
SELECT *
FROM dept RIGHT JOIN emp ON emp.deptno=dept.deptno;
(07)FULL join...on 连接条件
语法:table1 FULL JOIN table2 ON 连接条件
SELECT *
FROM emp e FULL JOIN emp m ON e.mgr=m.empno;
1.显示员工SMITH的姓名,部门名称,直接上级名称
SELECT e.ename,d.dname,m.ename
FROM emp e,emp m,dept d
WHERE e.deptno=d.deptno AND e.mgr=m.empno AND e.ename='SMITH';
2.显示员工姓名,部门名称,工资,工资级别,要求工资级别大于4级。
SELECT e.ename,d.dname,e.sal,s.grade
FROM emp e,dept d,salgrade s
WHERE e.deptno=d.deptno AND e.sal BETWEEN s.losal AND s.hisal
AND s.grade>4 ;
3.显示员工KING和FORD管理的员工姓名及其经理姓名。
SELECT e.ename,m.ename 管理的员工姓名,ms.ename 经理名
FROM emp e,emp m,emp ms
WHERE e.empno=m.mgr AND e.ename IN('KING','FORD')
AND m.mgr=ms.empno;
4.显示员工姓名,参加工作时间,经理名,参加工作时间,
要求参加时间比经理早。
SELECT e.ename,e.hiredate,m.ename,m.hiredate
FROM emp e,emp m
WHERE e.mgr=m.empno AND e.hiredate<m.hiredate;
SELECT * FROM emp;
SELECT * FROM salgrade;
思考练习题
2.显示30号部门的雇员所从事的不重复的工作名称,并显示30部门的所在地。
SELECT DISTINCT e.job,d.loc
FROM emp e,dept d
WHERE e.deptno=d.deptno AND e.deptno=30;
SELECT * FROM emp;
SELECT * FROM dept;
3.编写一个查询显示能获得奖金的雇员的姓名、部门名称、部门所在地。
SELECT e.ename,d.dname,d.loc
FROM emp e,dept d
WHERE e.deptno=d.deptno AND NVL(comm,0)>0;
4.编写一个查询显示在DALLAS工作的雇员的姓名、工作、部门编号及部门名称。
SELECT e.ename,e.job,e.deptno,d.dname
FROM emp e,dept d
WHERE e.deptno=d.deptno AND d.loc='DALLAS';
5.创建一个查询显示雇员的姓名、工作、部门名称、工资以及工资等级。
SELECT e.ename,e.job,d.dname,e.sal,s.grade
FROM emp e,dept d,salgrade s
WHERE e.deptno=d.deptno AND e.sal BETWEEN s.losal AND s.hisal;
二.分组查询
1.分组函数:又称为统计函数,集合函数
SUM():求和
AVG():求平均值
MAX():求最大值
MIN():求最小值
count():求个数
*:统计的表的记录数
列名:统计该列不为null的个数
注意:统计时,不对null值进行处理
SELECT SUM(sal),AVG(sal),MAX(sal),MIN(sal),COUNT(empno)
FROM emp;
SELECT 5.
FROM 1.
WHERE 2.
GROUP BY 3.分组字段,分组字段...
HAVING 4.组过滤条件
ORDER BY 6.
from->WHERE->GROUP BY->HAVING->SELECT->ORDER BY
WHERE 与having的区别
WHERE 是在分组钱进行过滤的,where的后面不能直接使用分组函数做比较
HAVING 是在分组后进行过滤的
--安装职务不同来分组统计工资总和,人数
SELECT job,SUM(sal),COUNT(empno)
FROM emp
GROUP BY job;
--查询emp表中不同的 职务
SELECT DISTINCT job
FROM emp;
SELECT job--,COUNT(*)
FROM emp
GROUP BY job;
--查询不同的领导工号的个数
SELECT COUNT(DISTINCT mgr)
FROM emp
--统计各个部门不同职务的员工薪水的总和,平均工资
SELECT deptno,job,SUM(sal),AVG(sal)
FROM emp
GROUP BY deptno,job
ORDER BY deptno;
--统计各个部门不同职务的员工薪水的总和,平均工资
--部门名称和职务
SELECT dname,job,SUM(sal),AVG(sal)
FROM emp,dept
WHERE emp.deptno=dept.deptno
GROUP BY dname,job
ORDER BY dname;
--统计各个部门不同职务的员工薪水的总和,平均工资
--部门名称,编号,位置和职务
SELECT dept.deptno,dname,loc,job,SUM(sal),AVG(sal)
FROM emp,dept
WHERE emp.deptno=dept.deptno
GROUP BY dept.deptno,dname,loc,job
ORDER BY dname;
--统计不同工资等级的员工人数,工资总和,工资平均值
SELECT s.grade,SUM(e.sal),round(AVG(e.sal),2),COUNT(*)
FROM emp e,salgrade s
WHERE e.sal BETWEEN s.losal AND s.hisal
GROUP BY grade;
--统计不同工资等级的员工人数,工资总和,工资平均值
--要求员工的人数大于二
SELECT s.grade,SUM(e.sal),round(AVG(e.sal),2),COUNT(*)
FROM emp e,salgrade s
WHERE e.sal BETWEEN s.losal AND s.hisal
GROUP BY grade
HAVING COUNT(*)>2;
--查询各个部门的平均工资大于2000的部门编号和平均工资
SELECT deptno,ROUND(AVG(sal),2)
FROM emp
GROUP BY deptno
HAVING AVG(sal)>2000;
3.分组函数的嵌套
注意:当select后面的分组函数嵌套使用时 select的后面不能直接使用列名
--查询部门平均工资最高的平均工资
SELECT MAX(round(AVG(sal)))
FROM emp
GROUP BY deptno;
课后作业
1.查询部门平均工资在2500元以上的部门名称及平均工资。
SELECT d.dname,round(AVG(sal),2)
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY d.dname
HAVING AVG(sal)>2500;
2.查询员工岗位中不是以“SA”开头并且
平均工资在2500元以上的岗位及平均工资,并按平均工资降序排序。
SELECT job,round(AVG(sal),2)
FROM emp
WHERE SUBSTR(ename,1,2)!='SA'
GROUP BY job
HAVING AVG(sal)>2500
ORDER BY AVG(sal)DESC
3.查询部门人数在2人以上的部门名称、最低工资、最高工资,
并对求得的工资进行四舍五入到整数位。
SELECT d.dname,round(MIN(e.sal)),round(MAX(e.sal))
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY e.deptno,d.dname
HAVING COUNT(e.empno)>=2;
4.查询岗位不为SALESMAN,工资和大于等于2500
的岗位及每种岗位的工资和。
SELECT job,SUM(sal)
FROM emp
WHERE job!='SALESMAN'
GROUP BY job
HAVING SUM(sal)>=2500;
5.显示经理号码和经理姓名,这个经理所管理员工的最低工资,
没有经理的KING也要显示,不包括最低工资小于3000的,
按最低工资由高到低排序。
SELECT e.mgr,m.ename,min(e.sal)
FROM emp e,emp m
WHERE e.mgr=m.empno --OR e.ename='king'
GROUP BY e.mgr,m.ename
HAVING MIN(e.sal)>=3000
SELECT m.empno,m.ename,MIN(e.sal)
FROM emp e,emp m
WHERE e.mgr=m.empno(+)
GROUP BY m.empno,m.ename
HAVING MIN(e.sal)>=3000
ORDER BY MIN(e.sal) DESC
6.写一个查询,显示每个部门最高工资和最低工资的差额。
SELECT deptno,MAX(sal)-MIN(sal)
FROM emp
GROUP BY deptno
SELECT * FROM emp;
三.子查询
子查询一般用()括起来
子查询出现的位置:SELECT,FROM,WHERE,HAVING
嵌套子查询:一个查询语句中嵌套了另一个查询语句:子查询的语句可以直接运行
单列子查询:子查询的返回结果是单行单列的,经常用在where,having
多行子查询:子查询的返回结果是单列多行的,经常用在where
多列子查询:子查询的返回结果是多行多列的,经常用在from,WHERE
1.单列子查询
---查询与smith相同职务的其他员工信息
SELECT job FROM emp WHERE LOWER(ename)='smith'
SELECT *
FROM emp
WHERE job=(SELECT job FROM emp WHERE LOWER(ename)='smith') AND LOWER(ename)!='smith'
---查询部门平均工资最高的平均工资和部门名称
SELECT MAX(AVG(sal))
FROM emp
GROUP BY deptno;
SELECT dname,round(AVG(sal),1)
FROM emp JOIN dept ON emp.deptno=dept.deptno
GROUP BY dname
HAVING AVG(sal)=(SELECT MAX(AVG(sal))
FROM emp
GROUP BY deptno);
2.多行子查询:
集合运算:IN
---查询与30部门职务相同的其他部门的员工信息
SELECT DISTINCT job FROM emp WHERE deptno=30;
SELECT *
FROM emp
WHERE job IN(SELECT DISTINCT job FROM emp WHERE deptno=30) AND deptno!=30
ANY:
=ANY:相当于in
>ANY:比子查询返回结果的最小值要大
---查询比10部门的最低工资要高的其他部门员工信息
SELECT *
FROM emp
WHERE sal>ANY(SELECT sal
FROM emp
WHERE deptno=10) AND deptno!=10;
<ANY:比子查询返回结果的最大值要小
---查询比20部门的最高工资要低的其他部门的员工信息
SELECT *
FROM emp
WHERE sal<ANY(SELECT sal
FROM emp
WHERE deptno=20) AND deptno!=20;
ALL:
=ALL:不存在现象
>ALL:比子查询的返回结果的最大值要大
---查询比20部门的所有人薪水都高的员工信息
SELECT *
FROM emp
WHERE sal>ALL(SELECT sal FROM emp WHERE deptno=20);
<ALL:比子查询的返回结果的最小值要小
--查询比10部门的所有人薪水都低的员工信息
SELECT *
FROM emp
WHERE sal<ALL(SELECT sal FROM emp WHERE deptno=10);
练习二
1.查询入职日期比10部门任意一个员工晚的
员工姓名、入职日期,不包括10部门员工
SELECT ename,hiredate
FROM emp
WHERE hiredate >ANY(SELECT hiredate
FROM emp
WHERE emp.deptno=10) AND emp.deptno!=10;
2.查询入职日期比10部门所有员工晚的
员工姓名、入职日期,不包括10部门员工
SELECT ename,hiredate
FROM emp
WHERE hiredate>ALL(SELECT hiredate
FROM emp
WHERE emp.deptno=10);
3.查询职位和10部门任意一个员工职位相同的
员工姓名,职位,不包括10部门员工
SELECT ename,hiredate
FROM emp
WHERE job = ANY(SELECT job
FROM emp
WHERE deptno=10) AND deptno!=10;
3.多列子查询
--查询与scott用户工资和服务都匹配的其他员工的信息
SELECT *
FROM emp
WHERE sal=(SELECT sal FROM emp WHERE UPPER(ename)='SCOTT')
AND job=(SELECT job FROM emp WHERE UPPER(ename)='SCOTT')
AND UPPER(ename)!='SCOTT';
SELECT *
FROM emp
WHERE (sal,job) IN(SELECT sal,job FROM emp WHERE UPPER(ename)='SCOTT')
AND UPPER(ename)!='SCOTT';
SELECT * FROM emp WHERE empno=7902;
--查询部门的名称,部门人数,部门最高工资,部门的最低工资,部门最低工资的姓名
SELECT deptno,COUNT(empno),MAX(sal),MIN(sal)
FROM emp
GROUP BY deptno;
SELECT dname,t.c,t.ma,t.mi,ename
FROM dept,emp,(SELECT deptno,COUNT(empno) c,MAX(sal) ma,MIN(sal) mi
FROM emp
GROUP BY deptno) t
WHERE emp.deptno=dept.deptno AND emp.deptno=t.deptno AND sal=t.mi
--查询职务和经理同员工SCOTT或BLAKB完全相同的员工姓名
--、职务、不包括SCOTT和BLAKB
SELECT job,mgr
FROM emp
WHERE UPPER(ename)='SCOTT' OR UPPER(ename)='BLAKB'
SELECT ename,job
FROM emp
WHERE (job,mgr) IN (SELECT job,mgr
FROM emp
WHERE UPPER(ename)='SCOTT' OR UPPER(ename)='BLAKB')
--查询不是经理的员工姓名
SELECT ename
FROM emp
WHERE empno NOT IN(SELECT DISTINCT mgr
FROM emp
WHERE mgr IS NOT NULL);
四.分页查询
oracle中
1.rownum:伪劣:从1开始递增,
---查询emp表中的前5行记录
SELECT *
FROM emp
WHERE ROWNUM<=5;
ROWNUM在做比较运算时,只能使用<,<=,不能使用>,>=
---查询emp表中的第5到第10条记录
SELECT ROWNUM r,emp.*
FROM emp;
SELECT ROWNUM ,t.*
FROM (SELECT ROWNUM r,emp.*
FROM emp) t
WHERE t.r BETWEEN 5 AND 10;
--查询emp表中的最后5条记录
SELECT ROWNUM,t.*
FROM (SELECT ROWNUM r,emp.* FROM emp) t
WHERE t.r>(SELECT COUNT(empno) FROM emp)-5;
--每页显示三条记录,查询第三页和第五页的员工信息
SELECT ROWNUM,t.*
FROM (SELECT ROWNUM r,emp.* FROM emp) t
WHERE t.r>(3-1)*3 AND t.r<=3*3 OR t.r>(5-1)*3 AND t.r<5*3;
2.topn
---查询工资最高的员工信息
SELECT * FROM emp ORDER BY sal DESC;
SELECT *
FROM (SELECT * FROM emp ORDER BY sal DESC) t
WHERE ROWNUM<=1;
--查询工资最高的前5位的员工信息
SELECT *
FROM (SELECT * FROM emp ORDER BY sal DESC) t
WHERE ROWNUM<=5;