什么叫子查询?
子查询也叫嵌套查询,是指嵌入在其他sql语句中的select语句。
单行子查询
单行子查询是指只返回一条记录的子查询语句。
查询工资最高的人的信息
select * from emp where sal = (select max(sal) from emp);
显示部门平均工资低于2000的部门的员工信息
select * from emp where deptno in (select deptno from emp group by deptno having avg(sal)<2000);
多行子查询
多行子查询是指返回多行数据的子查询。
查询和部门10 工作相同的雇员的名字,岗位,工资,部门号
- 先查询部门10有哪些岗位。
select distinct(job) from emp where deptno=10;
- 显示这些岗位的员工
select * from emp where job in (select distinct(job) from emp where deptno=10);
在子查询中使用all操作符 [熟悉]
显示工资比部门30所有员工的工资都高的员工姓名 【要大于所有】
select * from emp where sal > all(select sal from emp where deptno=30);
在子查询中使用any操作符 [熟悉]
显示工资比部门30任意员工的工资都高的员工姓名 【只要大于一个】
select * from emp where sal > any(select sal from emp where deptno=30);
多列子查询
查询和SCOTT部门和岗位完全相同的所有雇员。
思路1:
使用两个子查询分别查询
select * from emp where deptno = (select deptno from emp where ename='SCOTT') and job = (select job from emp where ename='SCOTT');
思路2:
使用括号 oracle特有的,其他数据库不一定支持。
select * from emp where (deptno,job)= (select deptno,job from emp where ename='SCOTT');
使用子查询创建新表
写法:create 新表名 as select from 旧表名
create table empbak as select * from emp where 1=0;--创建空表
create table empbak2(id,name,sal) as select empno,ename,sal from emp;--创建有内容表
使用子查询自我复制数据
写法:insert into 新表名[列名] select [*,列名] from旧表。
insert into empbak(empno,ename,job,mgr,hiredate,sal,comm,deptno) select * from emp;
insert into empbak(empno,ename) select * from emp;--错误写法,值过多
insert into empbak(empno,ename) select empno,ename from emp;
合并查询
union 用于取得两个结果集的并集,自动去掉重复的行。
select * from emp union select * from emp;--14条记录
union all 将两个结果集相加,不会去掉重复的行
select * from emp union all select * from emp;--28条记录
intersect 取交集,自动去掉重复的行。
select * from emp where sal>800 intersect select * from emp where sal>2000;
minus 取差集,自动去掉重复的行。
select * from emp where sal>800 minus select * from emp where sal>2000;
--不同表 取出相同类型的列 也可以使用 建议使用别名
select empno idno,ename idname from emp union select deptno idno,dname idname from dept;
select empno ,ename from emp union select deptno ,dname from dept;
笛卡尔集 交叉连接 【熟悉cross join】
在多表查询的时候,如果不带任何条件,则会出现笛卡尔集。
select * from emp;--14条记录
select * from dept;--4条记录
select * from emp,dept;--56条记录 隐式交叉连接
select * from emp cross join dept;--显示交叉连接
select * from salgrade;--5条记录
select * from dept,emp,salgrade;--280条记录
select * from dept cross join emp cross join salgrade;
笛卡尔集出现原理:
从dept中取出一条记录,分别于emp中的每一条记录匹配。
直到dept中的所有记录于emp中的所有记录全部匹配。
怎样避免笛卡尔集?
多表查询的条件至少不能少于表的个数-1.
等值连接
一个用户查询请求涉及到多个表的时候,连接多个表的条件为=时,就是等值连接查询。
在实际开发中,我们不可避免的需要对两张或是两张以上的表进行联合查询,比如显示雇员名字,雇员工资以及所在部门的名字。
--普通写法
select emp.ename,emp.sal,dept.dname from dept ,emp where dept.deptno = emp.deptno;
--正确写法 【不建议】
select ename,sal,dname from dept ,emp where dept.deptno = emp.deptno;
--错误写法,未明确定义列
select ename,sal,dname,deptno from dept ,emp where dept.deptno = emp.deptno;
--使用别名 [推荐写法]
select t2.ename,t2.sal,t1.dname from dept t1,emp t2 where t1.deptno = t2.deptno;
显示部门号为10的部门名,员工名和工资
select t1.ename,t1.sal,t2.dname from emp t1, dept t2 where t1.deptno=t2.deptno and t1.deptno=10;
非等值连接
一个用户查询请求涉及到多个表的时候,连接多个表的条件不是=时,就是非等值连接查询;
查询工资级别为1的员工信息。
select * from emp t1,salgrade t2 where t2.grade=1 and t1.sal between t2.losal and t2.hisal;
显示各个员工的姓名,工资以及工资级别。
select emp.ename,emp.sal,salgrade.grade from emp,salgrade where emp.sal between salgrade.losal and salgrade.hisal;
自然连接 【熟悉】
自然连接是通过对参与表关系中所有同名的属性对取等(即相等比较)来完成的,故无须自己添加连接条件
select * from emp natural join dept;--有同名列场景
select * from emp,dept where emp.deptno = dept.deptno;--效果等价
select * from emp natural join salgrade;--如果没有同名列 生成笛卡尔集
using连接 【熟悉】
相比较natural 更加灵活,可以指定多个列。
需要使用() ()内可以有多个列,但必须是两者都有的列,使用逗号分隔。
select * from emp join dept using (deptno);
select * from emp,dept where emp.deptno = dept.deptno;--效果等价
on连接 【熟悉】
相比较using更加灵活,可以指定不同列名。
select * from emp join dept on emp.deptno = dept.deptno;
自连接
显示员工JONES的上级领导的姓名
select * from emp where empno = ( select mgr from emp where ename = 'JONES');
显示所有员工和他上级的姓名?
思路 把emp看成两张表。(worker,manager)
select worker.ename,manager.ename from emp worker,emp manager where worker.mgr = manager.empno;
疑惑?
只显示了13条记录,KING没有显示,因为他没有上级。
Oracle的连接分类【了解】
oracle的连接分为内连接和外连接。
什么叫内连接?
内连接实际上就是利用where子句对两张表形成的笛卡尔集进行筛选。是开发中用的最多的连接查询,前面部分我们学习的都是内连接。
基本语法:
select 列名1,…… from 表1 inner join 表2 on 查询条件;
效果等同于select 列名1,…… from 表1,表2 where 查询条件;
外连接
外连接分成左外联,右外联,完全外联。
外连接 左连接
如果左表的记录不能和右表记录进行关联也要展示。
场景:有学生5名,其中3名学生缺席考试。
create table stu(id number,name varchar2(20));
create table exam(id number,grade number);
insert into stu values(1,'小明');
insert into stu values(2,'张三');
insert into stu values(3,'李四');
insert into stu values(4,'王五');
insert into stu values(5,'赵六');
insert into exam values(1,90);
insert into exam values(2,100);
select * from stu,exam where stu.id = exam.id;--没有参加考试的学生将不能显示
select * from stu left join exam on stu.id = exam.id;--没有参加考试的学生可以显示
select * from stu,exam where stu.id = exam.id(+);--另外的写法
外连接 右连接
如果右表的记录不能和左表关联也要展示
场景:有插班生进行考试,插班生id在学生信息表中没有。
insert into exam values(12,100);
select * from stu right join exam on stu.id = exam.id; --显示插班生考试成绩
select * from stu,exam where stu.id(+) = exam.id;--另一种写法
select * from exam left join stu on stu.id = exam.id;--此种写法跟表名顺序相关,左右连互转
select * from stu,exam where exam.id = stu.id(+);--此种写法与表名的顺序无关,跟字段相关
外连接 完全外联
不管是否有匹配记录,都显示出来。
select * from stu full outer join exam on stu.id = exam.id;
select * from stu full join exam on stu.id = exam.id;
三表连接
查询员工的员工信息,部门名称,工资级别
select t1.*,t2.dname,t3.grade from emp t1,dept t2,salgrade t3
where t1.deptno = t2.deptno
and t1.sal between t3.losal and t3.hisal;