Posts SQL练习——多表查询
Post
Cancel

SQL练习——多表查询

多表查

交叉连接 cross join

一般不用(因为无用信息太多)

1
select * from emp cross join dept -- 依次从m行的emp中取一行emp,和n行dept中的每一行进行组合,也就是会产生一个nxm行的表格
1
2
3
4
-- 根据以上结合的结果,如何查找到Smith的人所在的部门名称
select emp.ename, dept.deptno, dept.dname from emp 
	cross join dept
 where emp.deptno = dept.deptno and emp.ename = 'SMITH';

缺点:

  • 直接叉乘,得到的是全部集合(数据量太大)
  • 然后才能where进行条件运算(性能太差)

内连接 inner join

可简写为join

1
select * from emp inner join dept on '条件语句'
1
2
3
4
5
6
7
8
-- 查找MANAGER岗位的所有员工,包括编号、姓名、部门号、部门名称
select emp.empno, emp.ename, dept.deptno, dept.dname
	from emp inner join dept
	on emp.deptno = dept.deptno and emp.job = 'MANAGER'
-- 查找reserch部门的所有员工的信息
select dept.dname, emp.empno, emp.ename, emp.job, emp.mgr, emp.hiredate, emp.sal, emp.comm, emp.deptno
	from emp inner join dept
	on dept.dname = upper('research') and emp.deptno = dept.deptno;
非等值连接
1
2
3
4
5
6
7
8
9
10
-- 显示一个人的薪水等级
select e.ename, e.sal, s.grade from emp e 
	join salgrade s
	on e.sal >= s.losal and e.sal <= s.hisal
	order by s.grade ASC;

select e.ename, e.sal, s.grade from emp e 
	join salgrade s
	on e.sal between s.losal and s.hisal
	order by s.grade ASC;
1
2
3
4
5
6
-- 显示员工完整信息,包括部门名称
select e.*, d.* from emp e
	join salgrade s 
		on sal between losal and hisal
	join dept d
		on dept.deptno = emp.deptno;
1
2
3
4
5
-- 统计每一个工资等级的员工人数
select grade, count(e.empno) from emp e
	join salgrade s
		on e.sal between s.losal and s.hisal
	group by grade;
自连接
1
2
3
4
5
-- 查找员工与其上级的编号,姓名
select e1.empno, e1.ename, e2.empno, e2.ename from emp e1
	join emp e2
	on e1.mgr = e2.empno;
-- 可以发现,结果中少了boss的信息

连接(等值连接、非等值连接、自连接)中,一张表离得记录必须得再另一张表中存在匹配的记录,否则不能出现在结果集合中

外连接

  • Left \ Rigth \ Full outer join

    1
    2
    3
    4
    
    -- 查找所有职工,并显示出其上级的姓名、编号
    select * from emp e1
    	left outer join emp e2
    	on e1.mgr = e2.empno
    

    对于左连接的理解

    • 先按内连接查出所有数据并显示(能满足on的条件都显示出来)

    • 如果左边无法根据 on 匹配出相应的右边的数据,也要显示出来,但右边会写空

      1
      2
      3
      4
      5
      
      -- 查询所有部门的人数清单,部门编号,名称,人数
      select d.deptno, d.dname, nvl(T.cnt, 0) 
      	from dept d left outer join 
      		(select e.deptno, count(e.empno) cnt from emp e group by e.deptno) T
      	on d.detpno = T.deptno
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      
      -- 哪些员工没有下属(不是别人领导)
      -- 外连接 + 匹配表 pk is null 表示否定问题,不是,不包括,等
      -- 右连接:
      select e2.empno, e2.ename from emp e1 
      	right outer join emp e2
      	on e1.mgr = e2.empno
      	where e1.empno is null
      -- 左连接:
      select e1.empno, e1.ename from emp e1
      	left outer join emp e2
      	on e2.mgr = e1.empno
      	where e2.empno is null
      
      1
      2
      3
      4
      5
      
      -- 查出员工里没有叫SMITH的部门
      select * from dept d
      	left outer join emp e
      	on e.deptno = d.deptno and e.ename = 'SMITH'
      	where e.empno is null;
      

课后问题

1
2
3
4
-- 每一个部门的收入大户,收入是多少,精确到个人
select e.deptno, e.deptno, e.ename, T.maxsal from emp e
	join (select e.deptno, max(e.sal) maxsal from emp e group by e.deptno) T
	on e.deptno = T.deptno and e.sal = T.maxsal;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 求平均薪水大于1600的部门号,部门名称
-- 在外面筛选
select d.deptno, d.dname from dept d
join (select e.deptno, avg(e.sal) avgsal from emp e group by e.deptno) T
on d.deptno = T.deptno and T.avgsal > 1600;

-- 在里面筛选
select d.deptno, d.dname from dept d
join (
    	select e.deptno, avg(e.sal)
      	from emp e group by e.deptno
     	having avg(e.sal)>1600
     ) T
on d.deptno = T.deptno;
This post is licensed under CC BY 4.0 by the author.