目录
一、表连接
(一)内连接 inner join,等值连接
(二)外连接 outer join,等值连接
1、左外连接 left{outer} join
2、右外连接 right{outer} join
3、全外连接 full{outer} join
(三)不等值连接
(四)自连接
(五)用where的方式进行表连接
1、显示两张表共有的部分,没有(+)加号是内连接(inner join)
2、显示左表全部的信息,(+)加号在等号右边是左连接(left join)
3、显示右表全部的信息,(+)加号在等号左边是右连接(right join)
(六)总结
1. on 和 where 的区别
2. 内连接 inner join,显示双方共有的部分
3. 等值连接 =
4. 不等值连接 <>、<、>、=、!=
5. 自连接
6. 外链接
二、子查询
(一)单行单列
(二)多行单列、多列
三、子查询的分类
(一)非相关子查询(标准子查询)(嵌套子查询)
(二)相关子查询
(三)exists的用法
(四)in的特殊用法
(五)with as 用法
1、要点:
四、总结
五、可以学习的练习
六、练习
sql的分类:
DQL(Data Query Language):数据查询语言
DDL(Data Definition Language):数据定义语言
DML(Data Manipulation Language):数据操纵语言
DCL(Data Control Language):数据控制语言
DTL(Data Transaction Language):数据事务语言
TCL(Transaction Control Language):事务控制语言
只显示两张表共有的数据 (满足关联条件的数据显示,不满足关联条件的数据不显示)
--语法
select 列 from 表1
inner join 表2
on 表1.关联列=表2.关联列
--练习
select*from emp
inner join dept
on emp.deptno=dept.deptno
select *from emp a
inner join salgrade b
on a.sal between b.losal and b.hisal
显示左表的全部数据和右表满足关联条件的数据
select 列
from 表1--左表
left join 表2 --右表
on 表1.关联列=表2.关联列
显示右表的全部数据和左表满足关联条件的数据
select 列
from 表1--左表
right join 表2 --右表
on 表1.关联列=表2.关联列
显示两张表共有和独有的数据
select 列
from 表1
full join 表2
on 表1.关联列=表2.关联列
select *
from emp
full join dept
on emp.deptno=dept.deptno
练习:
--1. hr的employees和departments连接到一起显示
select *
from employees e
inner join departments d
on d.department_id=e.department_id
--2. 把deparments的全部数据显示在左边,employees的数据显示在右边
select *
from departments d
left join employees e
on e.department_id=d.department_id
--3. 显示employees的全部数据和departments符合关联条件的数据
select *
from employees e
inner join departments d
on e.department_id=d.department_id
--4. 显示departments的全部数据和employees符合关联条件的数据
select *
from departments d
inner join employees e
on e.department_id=d.department_id
--5. 显示两张表共有的和独有的数据
select *
from departments d
full join employees e
on e.department_id=d.department_id
--语法
select 列
from 表1
inner join 表2
on > < >=
--举例
select sal,b.*
from emp a
inner join salgrade b
on a.sal between b.losal and b.hisal
--查询员工编号、姓名及其经理编号、经理姓名
select a.empno ,a.ename,a.mgr,b.empno,b.ename
from emp a
inner join emp b
on a.mgr=b.empno
--where的方法不能显示两表全部数据(不能全外连接)
select*
from emp a,dept b
where a.deptno=b.deptno
select*
from emp a,dept b
where a.deptno=b.deptno(+)
select*
from emp a,dept b
where a.deptno(+)=b.deptno
/*笛卡尔积:
使用where进行多表连接但是没有加关联条件时出现
数据量较大时会造成数据库很慢
一般应避免出现笛卡尔积
*/
--emp dept连接后显示部门是10或30或者40部门的员工姓名部门编号、部门所在地,按照部门编号排序
select a. ename,b.deptno,b.loc
from emp a,dept b
where a.deptno(+)=b.deptno and b.deptno in(10,30,40)
order by b.deptno
select a. ename,b.deptno,b.loc
from emp a
right join dept b
on a.deptno=b.deptno
where b.deptno in (10,30,40)
order by b.deptno
--查询各个部门的名称和员工人数
select dname,count(ename)
from emp e,dept d
where e.deptno(+)=d.deptno
group by dname
select dname,count(ename)
from dept b
left join emp e
on b.deptno=e.deptno
group by dname
on 是对连接前的数据进行限制。即连接的前提条件
where 是对连接后的数据进行限制
同一张表自己连接,可以是inner join、outer join、等值、不等值
(1)左连接--左表数据全部显示,右表满足条件的显示不满足条件的显示为空
(2)右连接--右表数据全部显示,左表满足条件的显示不满足条件的显示为空
(3)全外连接--显示双方两表共有的和独有的数据
tip:工作中一般用左连接(left join / where =(+))
=========================================================================
=========================================================================
什么是子查询?在结果集里继续查询,即——在一个sql语句里再嵌套多个sql。
子查询先于主查询独立执行,返回的结果供主查询使用。
命令 | 执行顺序 | 子查询可以用在的地方 |
with as | 1 | 一定要接子查询★ |
select | 8 | 可以,但是不建议(标量子查询) |
from | 2 | 可以,子查询当临时表用★(内联视图) |
inner join | 3 | 可以,子查询当临时表用 |
on | 4 | 可以接单行单列,一般不用 |
where | 5 | 可以,经常用★ |
group by | 6 | 不可以 |
having | 7 | 可以 |
order by | 9 | 可以,必须是单行单列 |
返回的结果是一个值,可以放在可以放一个值得地方。
可以把子查询当集合使用,可以使用多行比较运算符 in、any、all、exists
·【all】和【any】 必须和单行比较运算符结合使用
·【>all】 大于最大的
·【>any】 大于最小的
·【=all】 空
·【=any】 相当于 【in】
先运行子查询,再运行主查询
--查询emp表工资大于30部门所有人的员工工资
select * from emp where sal
--多列:经常当做临时表使用
--查询emp表中20部门的员工中工资大于2000的员工姓名 、工作
select ename ,job,sal
from (select *from emp where deptno=20)
where sal>2000
--查询(emp表中和‘SCOTT’的 工作一样的)员工姓名,工作,经理编号
select ename,job,mgr
from emp
where job=(select job from emp where ename='SCOTT')
--查询emp表中和员工编号是7788的员工部门相同的员工编号、姓名、部门编号
select empno,ename,deptno
from emp
where deptno =(select deptno from emp where empno='7788')
--查询1981年入职的员工中,经理是KING的员工信息
select * from emp
where mgr=(select empno from emp where ename='KING')and to_char(hiredate,'yyyy')=1981
--查询部门所在地是NEW YORK 的员工信息(用表连接和子查询两种办法)
select * from EMP
where DEPTNO =(select DEPTNO from DEPT where loc='NEW YORK' )
SELECT *
FROM DEPT D
INNER JOIN EMP E ON D.DEPTNO =E.DEPTNO
WHERE D.LOC='NEW YORK'
先运行主查询,再运行子查询,子查询提前运行不能得到明确的结果
·子查询在主查询的结果的基础上进行查询
·子查询和主查询在执行过程中互相依赖
select empno,ename,(select dname from dept b where a.deptno=b.deptno)
from emp a
改写:
select empno,ename,dname
from emp a
inner join dept b
on a.deptno=b.deptno
select empno,ename,dname
from emp a ,dept b
where a.deptno=b.deptno
判断是否存在,如果子查询返回>=1列(有返回值),那么执行上面的sql
如果子查询返回空,那么结果为空。
select * from emp
where exists(select 123 from dual)--非相关子查询
--关心的是子查询是否有返回值
select *
from emp a
where exists(select 1 from dept b where a.deptno=b.deptno and loc='NEW YORK')
select a.*
from emp a
inner join dept b
on a.deptno=b.deptno and loc='NEW YORK'
--not in 向 not exists 改写时,要注意去空值。
--查询经理不是KING也不是SCOTT的员工信息
select *
from emp a
inner join emp b
on a.mgr=b.empno
where b.ename not in('KING','SCOTT')
---------------------------------------------------------
select * from emp a
where not exists(select 1 from emp b where a.mgr=b.empno
and b.ename in ('KING','SCOTT'))
and mgr is not null
---------------------------------------------------------
select * from emp a
where mgr not in
(select empno from emp where ename in ('KING','SCOTT'))
--查询emp表中和经理编号是7788的员工的工作和部门编号相同的员工信息
select job,deptno
from emp
where mgr=7788
单列多行子查询
select *
from emp
where job in(select job from empwhere mgr=7788)
and deptno in(select deptno from emp where mgr =7788)
in的特殊用法如下
select *
from emp
where(job,deptno) in (select job,deptno from emp where mgr=7788)
--查询emp表中和经理是KING的员工的工作、部门编号相同的员工信息
select *
from emp
where (job,deptno,ename)
in(select job,deptno,ename from emp
where mgr=(select empno from emp where ename='KING'))
(1)看懂别人的
(2)尝试让自己会写,锻炼自己的改写能力
(4)在sql优化上,性能更好
(5)可以简化多次查询的SQL,增强可读性和提高性能,多次复用
(6)要和select语句一起执行
(7)whih as 可以给多个子查询起别名,用逗号连接,最后一个不加逗号
(8)with as -----必须和下面的select语句一起执行
with a as(select ename,deptno,sal,job from emp),
b as(select deptno,dname from dept)
select dname,sum(sal)
from a,b
where a.deptno=b.deptno
group by dname
order by sum(sal) desc
-----------------------------------------------------------------------
-----------------------------------------------------------------------
--查询每个部门工资最高的
--员工编号,姓名,职位,工资,部门编号,部门名称
--结果按照部门编号排序
with a as (select deptno,max(sal) maxsal from emp group by deptno)
select empno,ename,job,sal,e.deptno,dname
from emp e
inner join dept d
on e.deptno=d.deptno
inner join a
on e.deptno=a.deptno
where a.deptno=e.deptno and a.maxsal=e.sal
-----------------------------------------------------------------------
with a as (select deptno,max(sal) maxsal from emp group by deptno)
select empno,ename,job,sal,e.deptno,dname
from emp e,dept d,a
where e.deptno=d.deptno and a.maxsal=e.sal and a.deptno=e.deptno
-----------------------------------------------------------------------
select empno,ename,job,sal,deptno
from emp
where(deptno,sal) in (select deptno,max(sal) from emp group by deptno)
--=======================================================================
--=======================
子查询:必须有关联条件
--=======================
1、非相关子查询
(1)单行单列--相当于一个值
(2)多行单列--可以作为一个结果集,要用多行比较运算符in、any、all、exists
(3)多列 --多用作临时表
2、相关子查询
(1)标量子查询--需要改写。即:select后的子查询需要改写
(2)exists 后的相关子查询可以和in/表连接互相改写
--=======================================================================
--=======================================================================
--=======================
with as:必须和select执行
--=======================
(1)可以简化SQL,增强可读性和提高性能
(2)多次复用
(3)要和select语句一起执行
(4)可以给多个子查询起别名,用逗号连接,最后一个不加逗号
with t1 as(select colum1,colum2,colum3 from table1),
t2 as(select colum1,colum2,colum3 from table2),
t3 as(select colum1,colum2,colum3 from table3)
select t1.*,t2.*.t3.*
from t1
left join t2 on t1.colum1 = t2.colum1
left join t3 on t1.colum1 = t3.colum1
--=======================================================================
--查询emp表每个部门的人数,平均工资,总工资
--最高工资,最低工资
--显示(最高工资减去最低工资)除以人数 最大的部门
select (g.d-g.e)/max(g.a)
from (select deptno,count(ename) a,avg(sal) b,sum(sal)c,max(sal) d,min(sal) e
from emp
group by deptno) g
group by (g.d-g.e)
-----------------------------------------------------------------------------------
select g.deptno
from (select deptno,
count(ename) a,
avg(sal) b,
sum(sal)c,
max(sal) d,
min(sal) e
from emp
group by deptno
) g
where (g.d-g.e)/g.a =(select max((t.d-t.e)/t.a)
from (select deptno,
count(ename) a,
avg(sal) b,
sum(sal)c,
max(sal) d,
min(sal) e
from emp
group by deptno
) t
)----这里不可以直接引用
-----------------------------------------------------------------------------------
--改写成with as
with g as (select deptno,count(ename) a,avg(sal) b,sum(sal)c,max(sal) d,min(sal) e
from emp
group by deptno)-----------反复用的的表就可以考虑用with as
select g.deptno
from g
where (g.d-g.e)/g.a=(select max((g.d-g.e)/g.a) from g)---这里就可以直接引用
-----可以学习的点在于,能否直接引用
--1、查询emp表中和'SCOTT'工作一样的员工姓名、工作、经理编号
select*
from(select ename,job,mgr from emp )
where job=(select job from emp where ename='SCOTT')
----------------
select ename,job,deptno
from emp
where job=(select job from emp where ename='SCOTT')
/*============================================================================*/
--2、查询emp表中 和【员工编号】是7788 的【员工部门相同】的员工编号、姓名、部门编号
select empno,ename,deptno
from emp
where deptno=(select deptno from emp where empno=7788)
-------------------
select *
from (select empno,ename,deptno from emp )
where deptno=(select deptno from emp where empno=7788)
/*============================================================================*/
--3、查询1981年入职的员工中,经理是KING的员工信息
select*
from emp
where to_char(hiredate,'yyyy')=1981
and mgr=(select empno from emp where ename='KING')
-------------------------
select* from emp a
inner join emp b
on a.mgr=b.empno
where to_char(a.hiredate,'yyyy')=1981 and b.ename='KING'
/*============================================================================*/
--4、查询部门所在地是NEW YORK的员工信息(表连接和子查询)
---表连接的方法
select*
from emp a
inner join dept d
on a.deptno=d.deptno
where d.loc='NEW YORK'
----------------------
select*
from emp a,dept d
where a.deptno=d.deptno and loc='NEW YORK'
-----------------------------------------------