Day31 Oracle 2 多表查询和子查询

SQL99的多表连接查询

SQL1999规范中规定的连接查询语法

select 字段列表
from table1
[cross join table2] | //1:交叉连接
[natural join table2] | //2:自然连接
[join table2 using (字段名)] | //3:using子句
[join table2 on (table1.column_name
= table2.column_name)] | //4:on子句
[(left | right | full outer) join table2
on (table1.column_name = table2.column_name)]; //5:左/右/满外连接

交叉连接

Cross join产生了一个笛卡尔集,其效果等同于在两个表进行连接时未使用WHERE子句限定连接条件;
可以使用where条件从笛卡尔集中选出满足条件的记录。

用法举例
select dept.deptno,dname,ename,job
from dept cross join emp;

自然连接

Natural join基于两个表中的全部同名列建立连接
从两个表中选出同名列的值均对应相等的所有行
如果两个表中同名列的数据类型不同,则出错
不允许在参照列上使用表名或者别名作为前缀
自然连接的结果不保留重复的属性

举例:
select empno, ename, sal, deptno, dname
from emp natural join dept
where deptno = 10;

Using子句

如果不希望参照被连接表的所有同名列进行等值连接,自然连接将无法满足要求,可以在连接时使用USING子句来设置用于等值连接的列(参照列)名。

using子句引用的列在sql任何地方不能使用表名或者别名做前缀

举例:
select e.ename,e.ename,e.sal,deptno,d. dname
from emp e join dept d
using(deptno)
where deptno=20

On子句

自然连接的条件是基于表中所有同名列的等值连接
为了设置任意的连接条件或者指定连接的列,需要使用ON子句
连接条件与其它的查询条件分开书写
使用ON 子句使查询语句更容易理解

select ename,dname
from emp join dept on emp.deptno=dept.deptno
where emp.deptno=30;
select empno, ename, sal, emp.deptno, dname
from emp join dept
on (emp.deptno = dept.deptno and job=’SALESMAN);

外连接

左外联接
两个表在连接过程中除返回满足连接条件的行以外,还返回左表中不满足条件的行,这种连接称为左外联接。
右外联接
两个表在连接过程中除返回满足连接条件的行以外,还返回右表中不满足条件的行,这种连接称为右外联接。
满外联接
两个表在连接过程中除返回满足连接条件的行以外,还返回两个表中不满足条件的所有行,这种连接称为满外联接。

内连接:在SQL99规范中,内连接只返回满足连接条件的数据

外连接举例
左外连接
select deptno, dname,empno,ename,job
from dept left join emp
using(deptno);
右外连接
select deptno, dname,empno,ename,job
from dept right join emp
using(deptno);
满外连接
select deptno, dname,empno,ename,job
from dept full join emp
using(deptno);

三表连接使用on创建连接

创建城市表City,部门表Dept1,员工表EMP1
部门表城市id参考城市表,员工表部门编号参考部门表

显示所有员工的编号,姓名和部门名称,城市编号

select e.empno,e.ename,d.dname,c.name
from emp1 e
join dept1 d on e.deptno = d.deptno –连接条件
join city c on d.loc = c.id –连接条件
where empno > 7800

查询每个员工的部门名称和工资等级
select e.empno,e.ename,e.sal,e.deptno,d.dname,sg.*
from emp e
join dept d
on d.deptno = e.deptno
join salgrade sg
on e.sal between sg.losal and sg.hisal

自连接

使用举例:查询每个员工的工号、姓名、经理姓名
select * from emp e join emp m on(e.mgr = m.empno)

select e.empno,e.ename,e.mgr,m.empno,m.ename from emp e join emp m on(e.mgr = m.empno)
–没有上级的员工也显示
select e.empno,e.ename,e.mgr,m.empno,m.ename from emp e left join emp m on(e.mgr = m.empno)
–没有员工的上级(不就是底层员工吗)也显示,还是别显示了
select e.empno,e.ename,e.mgr,m.empno,m.ename from emp e right join emp m on(e.mgr = m.empno)

SQL92的多表连接查询

语法规则:
SELECT table1.column, table2.column
FROM table1, table2
WHERE table1.column1 = table2.column2;
特点
在 WHERE 子句中写入连接条件
当多个表中有重名列时,必须在列的名字前加上表名作为前缀
连接的类型:
等值连接 – Equijoin
非等值连接 – Non-equijoin
外连接 – Outer join
左外连接 右外连接
自连接 – Self join

笛卡尔集

select * from dept;//4条记录
select * from emp; ;//14条记录
select * from dept,emp; ;//4*14=56条记录

总结
检索出的行的数目将是第一个表中的行数乘以第二个表中的行数
检索出的列的数目将是第一个表中的列数加上第二个表中的列数
应该保证所有联结都有where子句,不然数据库返回比想要的数据多得多的数据

等值查询

select * from dept,emp where dept.deptno=emp.deptno;
select * from dept d,emp e where d.deptno=e.deptno;
select d.deptno,dname,loc,empno,ename,job from dept d,emp e where d.deptno=e.deptno;
select d.deptno,dname,loc,empno,ename,job from dept d,emp e where d.deptno=e.deptno and d.deptno=10
select d.deptno,dname,loc,empno,ename,job from dept d,emp e where d.deptno=e.deptno and loc=’DALLAS’;

当被连接的多个表中存在同名字段时,须在该字段前加上”表名.”前缀
可使用AND 操作符增加查询条件;
使用表别名可以简化查询
使用表名(表别名)前缀可提高查询效率;

SQL92的语法规则的缺点:

语句过滤条件和表连接的条件都放到了where子句中 。
当条件过多时,联结条件多,过滤条件多时,就容易造成混淆
SQL99修正了整个缺点,把联结条件,过滤条件分开来,包括以下新的TABLE JOIN的句法结构:
交叉连接(Cross join)
自然连接(Natural join)
使用Using子句建立连接
使用On子句建立连接
外连接( Outer join )
左外连接
右外连接
全外连接

子查询

子查询
问题引入
如何查得所有比“CLARK”工资高的员工的信息
select * from emp
where sal>(select sal from emp where ename=’CLARK’);
思考:查询工资高于平均工资的雇员名字和工资。
思考:查询和SCOTT同一部门且比他工资低的雇员名字和工资。
语法格式:
select 字段列表 from table
where 表达式 operator (select 字段列表 from table);
特点
子查询在主查询前执行一次
主查询使用子查询的结果

使用子查询注意事项

在查询是基于未知值时应考虑使用子查询
子查询必须包含在括号内
建议将子查询放在比较运算符的右侧,以增强可读性。

除非进行Top-N 分析,否则不要在子查询中使用ORDER BY 子句。

如果子查询返回单行结果,则为单行子查询,可以在主查询中对其使用相应的单行记录比较运算符

如果子查询返回多行结果,则为多行子查询,此时不允许对其使用单行记录比较运算符

单行子查询

单行子查询只返回一行记录
对单行子查询可使用单行记录比较运算符
< 、 > 、 = 、 >=、 <= 、 <>

举例:
select * from emp
where sal > (select sal from emp where empno = 7566);

思考:查询工资最高的雇员名字和工资。

查询职务和SCOTT相同,比SCOTT雇佣时间早的雇员信息
SELECT empno, ename, job FROM emp
WHERE job =(SELECT job FROM emp WHERE empno=7788)
AND hiredate < (SELECT hiredate FROM emp WHERE empno=7788);

查询工资比SCOTT高或者雇佣时间比SCOTT早的雇员的编号和名字
select empno,ename,sal,hiredate
from emp
where sal>(select sal from emp where ename=’SCOTT’) or hiredate<(select hiredate from emp where ename=’SCOTT’)

多行子查询

多行子查询返回多行记录
对多行子查询只能使用多行记录比较运算符
ALL 和子查询返回的所有值比较
ANY 和子查询返回的任意一个值比较
IN 等于列表中的任何一个

查询工资低于任何一个“CLERK”的工资的雇员信息。
查询工资比所有的“SALESMAN”都高的雇员的编号、名字和工资。
查询部门20中职务同部门10的雇员一样的雇员信息。

SELECT empno, ename, job,sal
FROM emp
WHERE sal < ANY (SELECT sal FROM emp WHERE job = ‘CLERK’) AND job <> ‘CLERK’;

SELECT empno, ename,sal
FROM emp
WHERE sal > ALL(SELECT sal FROM emp WHERE job= ‘SALESMAN’);

SELECT empno, ename, job FROM emp
WHERE job IN (SELECT job FROM emp WHERE deptno=10)
AND deptno =20;

不相关子查询

子查询不需要用到外查询的数据;子查询可以独立运行;自内而外

相关子查询

子查询需要用到外查询的数据;子查询不可以独立运行;自外而内

查询本部门最高工资的员工
–方法一,使用嵌套子查询(非关联子查询)
select * from emp a where (a.deptno,a.sal) in (select deptno,max(sal) from emp group by deptno)
–方法二,使用关联子查询/9-*********
select * from emp a where a.sal=(select max(sal) from emp where deptno=a.deptno)

查询在雇员中有哪些人是经理人
分析:有哪些人的empno号在mgr这个字段中出现过,应首先查询mgr中有哪些号 码, 然后再看有哪些人的雇员号码在此出现
select empno, ename from emp
where empno in (
select distinct mgr from emp
);
找出部门编号为20的所有员工中收入最高的职员
select * from emp
where sal >= all(
select sal from emp where deptno = 20)
and deptno = 20

查询每个部门平均薪水的等级
分析:首先将每个部门平均薪水求出来,然后把结果当成一张表,再用这张结果表和salgrade表做连接,以此求得薪水等级

先求出每个部门平均薪水的表t。
将t和salgrade进行关联查询就可以了。

select * from 
salgrade s, (select deptno,avg(sal) avg_sal 
        from emp group by deptno) t
where  t.avg_sal between s.losal and s.hisal;

小结

SQL99的多表连接查询

  • 交叉连接
  • 自然连接
  • Using连接
  • On连接
  • 外连接
  • 自连接

SQL92的多表连接查询
子查询

  • 单行子查询和多行子查询
  • 相关子查询和不相关子查询

连接查询-内连接

--SQL99多表连接查询
--查询员工信息及其部门信息
select * from emp  --只知道了部门的编号,不知道部门的其他信息:名称、地址

select * from emp
select * from dept where deptno = 20
select * from dept where deptno = 30  --目的达到了,但是是通过多条SQL语句实现的,效率低下

--解决方案:通过一条SQL语句查询多张表,得到一个结果  效率高  多表连接(join)查询

--交叉连接 cross join 结果没有实际意义,方便我们理解连接查询的原理 笛卡尔积
select * from dept  --4
delete from dept where deptno = 50 or deptno = 60;
select * from emp  -- 14
select * from emp  cross join dept  --56 =4*14
select * from dept cross join emp
--自然连接
--前提:必须有同名列
--操作过程:自动按照【所有的】同名列进行匹配,同名列只显示一次
--优点:简单
select * from emp natural join dept

select deptno, empno,ename,job,dname,loc from emp natural join dept
select deptno, empno,ename,job,dname,loc from emp natural join dept where job = 'MANAGER'
--建议给列名指定表名,直接定位,提高性能
select deptno,emp.empno,emp.ename,emp.job,dept.dname,dept.loc from emp natural join dept
where job = 'MANAGER'
--!!!同名列不能使用表名前缀
--缺点:直接使用表名,有些繁琐,表名可能太长。
--解决:可以使用别名
select deptno,e.empno,e.ename,e.job,d.dname,d.loc
from emp e
natural join dept d
where job ='MANAGER'

--using子句
--自然连接会自动按照所有的同名列进行匹配,如果只希望按照某个同名列进行匹配该怎么办?
--using中同名列还是只显示一次,不能使用前缀
select deptno,e.empno,e.ename,e.job,d.dname,d.loc
from emp e
join dept d
using(deptno)
where loc = 'CHICAGO'

--on子句
--万一两个表之间有关联字段,但是名称不同,此时就只能使用on子句
select * from dept
select * from emp

select * 
from emp e
join dept d
on(d.deptno = e.deptno)
--on子句中,关联列名称可能不同,必须指定前缀
select d.deptno,e.empno,e.ename,e.job,d.dname,d.loc
from emp e
join dept d
on(d.deptno = e.deptno)
where ename like '%A%'

--总结
--1.连接查询的好处:效率高  一条语句同时查询多个表
--2.连接查询多种形式(crossnaturalusingon),都离不开join
--3.实际开发中使用on最多,适应情况最广(不管是否有同名列),可读性高
--4.连接条件:crossnaturalusingon
--  筛选条件:where having
--SQL99优点:连接条件和筛选条件分开,更清晰

连接查询-外连接和三表连接

--外连接查询
select * from dept
select * from emp;
--有的部门是没有员工的:40
--有的员工的没有部门的:7788 scott
update emp set deptno = null where empno = 7788

--连接查询:查询员工及其部门信息
select *
from emp e
inner join dept d
on (e.deptno = d.deptno)

--只显示了匹配的数据,没有显示不匹配的数据(40部门 、scott员工)
--左外连接:在显示所有匹配数据的前提下,不匹配数据只显示没有部门的员工
select *
from emp e   
left outer join dept d
on (e.deptno = d.deptno)

--右外连接:在显示所有匹配数据的前提下,不匹配数据只显示没有员工的部门
select *
from emp e
right outer join dept d
on (e.deptno = d.deptno)


--全外连接:在显示所有匹配数据的前提下,不匹配数据两者都显示(没有部门的员工,没有员工的部门)
select *
from emp e
full outer join dept d
on (e.deptno = d.deptno)

--内连接和外连接
--内连接:inner join 只显示匹配的数据
--外连接:outer join 除了显示匹配的数据,还可以显示部分或者全部不匹配的数据
            --左外连接、右外连接、全外连接


--三张表的连接
--hr用户解除锁定
alter  user hr account unlock;
--修改密码
alter user hr identified by hr

select * from regions  --大区
select * from countries; --国家
select * from locations where country_id= 'CN' --所在地
select * from departments; --部门
select * from employees;--员工
select * from jobs;--岗位
select * from job_history where employee_id = 101  --岗位经历


--查询一个员工的编号、姓名、薪水和部门编号
select * from employees;
select employee_id,first_name,last_name,salary,department_id from employees

--查询一个员工的编号、姓名、薪水和部门编号、部门的名称、部门所在地的编号
select * from departments

select employee_id,first_name,last_name,salary,d.department_id,d.department_name,d.location_id
from employees e
join departments d
on (d.department_id = e.department_id)


--查询一个员工的编号、姓名、薪水和部门编号、部门的名称、部门所在地的编号,所在地名称
select * from locations

select employee_id,first_name,last_name,salary,d.department_id,
       d.department_name,d.location_id,l.street_address,l.country_id,c.country_name
from employees e
join departments d
on (d.department_id = e.department_id)
join locations l
on(d.location_id = l.location_id)
join countries c
on l.country_id = c.country_id
where e.salary > 10000 and d.department_name = 'Executive'

连接查询-自连接和SQL92连接

--三表连接查询示例2:查询工资等级,部门名称
--删除表
delete from emp2  --删除表中的数据
truncate table emp2;--删除表中的数据
drop table emp2;
drop table emp3;
drop table emp4;

select * from dept;
select * from emp;
select * from salgrade;
--查询员工的编号、姓名、工资、部门编号
select e.empno,e.ename,e.sal,e.deptno
from emp e
--查询员工的编号、姓名、工资、部门编号、部门的名称
select e.empno,e.ename,e.sal,e.deptno,d.dname
from emp e
join dept d
on (e.deptno = d.deptno)

--查询员工的编号、姓名、工资、部门编号、部门的名称,工资等级
select e.empno,e.ename,e.sal,e.deptno,d.dname,sg.grade
from emp e
left join dept d
on (e.deptno = d.deptno)
join salgrade sg
on(e.sal between sg.losal and sg.hisal)


--自连接
select * from emp;

--查询员工的编号,姓名,上级编号
select empno,ename,mgr from emp

--查询员工的编号,姓名,上级编号,上级的姓名
select e.empno,e.ename,e.mgr,m.empno,m.ename
from emp e
join emp m
on (e.mgr = m.empno) 

--没有上级的员工也显示出来(将董事长也显示出来)
select e.empno,e.ename,e.mgr,m.empno,m.ename
from emp e
left join emp m
on (e.mgr = m.empno) 


--SQL99的连接查询
--分类1(连接条件):交叉连接、自然连接,using子句、on子句
--分类2(是否显示匹配数据):内连接  外连接
--分类3:自连接、非自连接

--优点:连接条件和筛选条件分离,join连接



--SQL92的连接查询

--查询员工的编号、姓名、薪水,部门编号、部门名称
select *
from dept d,emp e

select e.empno,e.ename,e.sal,d.deptno,d.dname
from dept d,emp e
where d.deptno = e.deptno and sal > 2800

--查询员工的编号、姓名、薪水,部门编号、部门名称、工资等级
select e.empno,e.ename,e.sal,d.deptno,d.dname,sg.grade
from dept d,emp e,salgrade sg
where d.deptno = e.deptno and e.sal between sg.losal and sg.hisal 
      and sal > 2800
order by sal 

--SQL92:连接条件和筛选条件都在where子句中,没有分开

不相关子查询

--子查询
--1.单行子查询: 子查询的结果只有一条记录
  --1.1查得所有比“BLAKE”工资高的员工的信息
   select * from emp;
   select sal from emp where ename = 'BLAKE'
   select * from emp where sal > 2850

   select * from emp where sal > (select sal from emp where ename = 'BLAKE')

  --1.2查询工资高于平均工资的雇员名字和工资。
   select avg(sal) from emp
   select * from emp where sal > (select avg(sal) from emp)

  --1.3查询职务和SCOTT相同,比SCOTT雇佣时间早的雇员信息
  select job from emp where ename = 'scott' 
  select hiredate from emp where ename = 'scott' 
  select * from emp where job = (select job from emp where ename = 'scott') and hiredate < (select hiredate from emp where ename = 'scott' )



--2.多行子查询:子查询的结果包括多条记录,需要借助ANY,ALL,IN进行相关比较
  --2.1查询工资低于任意一个“CLERK”的工资的雇员信息。

   --思路1:单行子查询,低于任意一个,可以理解为低于最高的
   select max(sal) from emp where job ='CLERK'

   select * from emp where sal < ( select max(sal) from emp where job ='CLERK') and job !='CLERK'

   --思路2:多行子查询
   select sal from emp where job = 'CLERK'

   select * from emp where sal < ANY(select sal from emp where job = 'CLERK')
  --2.2查询工资比所有的“SALESMAN”都高的雇员的编号、名字和工资。
  --思路1:单行子查询
  select max(sal) from emp where job = 'SALESMAN'  --1600
  select * from emp where sal >(select max(sal) from emp where job = 'SALESMAN')

  --思路2:多行子查询
  select sal from emp where job = 'SALESMAN'
  select * from emp where sal > ALL (select sal from emp where job = 'SALESMAN')
  --2.3查询部门20中职务同部门10的雇员一样的雇员信息。
  --查询雇员信息
  --查询部门20中雇员信息
  --查询部门20中[职务同部门10的雇员一样]雇员信息
  select job from emp where deptno = 20  -- CLERK  MANAGER  ANALYST
   select job from emp where deptno = 10  --MANAGER  PRESIDENT  CLERK

  --首先知道10号部门有哪些职务
 select job from emp where deptno = 10  --MANAGER  PRESIDENT  CLERK

 select * from emp where deptno = 20 and job = ANY('MANAGER',  'PRESIDENT',  'CLERK')
 select * from emp where deptno = 20 and job IN ('MANAGER',  'PRESIDENT',  'CLERK')

  --2.4查询在雇员中有哪些人是管理人(有下级)  含义:员工的编号出现在mgr列就是管理人
  select * from emp

  select distinct mgr from emp where mgr is not null  --所有管理人的编号 

  select * from emp where empno in (select distinct mgr from emp where mgr is not null)

  --不相关子查询(单行子查询、多行子查询)
         -- 子查询可以独立运行,先运行子查询,再运行外查询
  --相关子查询

相关子查询

--不相关子查询
  --子查询可以独立运行
  --先执行子查询,再执行外查询
--相关子查询
  --子查询不可以独立运行
  --先执行外查询,再执行子查询

--查询本部门最高工资的员工
--查询本部门(10,20,30,40....)最高工资的员工  
--查询本部门(10)最高工资的员工 
  select * from emp e where e.deptno = 10 and sal = (select max(sal) from emp e2 where e2.deptno = 10 )
  select * from emp e where e.deptno = 20 and sal = (select max(sal) from emp e2 where e2.deptno = 20 )
  select * from emp e where e.deptno = 30 and sal = (select max(sal) from emp e2 where e2.deptno = 30 )
  select * from emp e where e.deptno = 40 and sal = (select max(sal) from emp e2 where e2.deptno = 40 )

  select * from emp e where sal = (select max(sal) from emp e2 where e2.deptno = e.deptno )
  select * from emp e where sal = (select max(sal) from emp  where deptno = e.deptno )

--查询工资高于其所在部门的平均工资的那些员工
--查询10部门中工资高于10部门的平均工资的那些员工
  select * from emp where deptno = 10 and sal >(select avg(sal) from emp where deptno = 10)
  select * from emp where deptno = 20 and sal >(select avg(sal) from emp where deptno = 20)
  select * from emp where deptno =30 and sal >(select avg(sal) from emp where deptno = 30)

  select * from emp e where  sal >(select avg(sal) from emp where deptno = e.deptno)

--子查询和连接查询结合使用
--查询每个部门平均薪水的等级

  --查询每个部门平均薪水
  select avg(sal) from emp

  select deptno,avg(sal)
  from emp
  where deptno is not null
  group by deptno
  --查询每个员工薪水的等级
  select empno,ename,sal,sg.*
  from emp e
  join salgrade sg
  on( e.sal between sg.losal and sg.hisal)


  --查询每个部门平均薪水的等级

 select deptno,asal,sg.*
  from (select deptno,avg(sal) asal   from emp   where deptno is not null   group by deptno) e
  join salgrade sg
  on( e.asal between sg.losal and sg.hisal)

--子查询分类
--相关子查询和不相关子查询
--单行子查询和多行子查询


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值