前面我们讲解的mysql表的查询都是对一张表进行查询,链接为这里写链接内容
今天来学习多表查询。
我们用一个简单的公司管理系统,有三张表EMP ,DEPT,SALGRADE来演示如何进行多表查询。
表内容如下:
创建部门表
drop table if exists dept;
create table if not exists dept
(
deptno INT(2) zerofill not null comment ‘部门编号’,
dname VARCHAR(14) comment ‘部门名称’,
loc VARCHAR(13) comment ‘部门所在地点’
);
创建雇员表
drop table if exists emp;
create table if not exists emp
(
empno INT(6) zerofill not null comment ‘雇员编号’,
ename VARCHAR(10) comment ‘雇员姓名’,
job VARCHAR(9) comment ‘雇员职位’,
mgr INT(4) zerofill comment ‘雇员领导编号’,
hiredate DATETIME comment ‘雇佣时间’,
sal DECIMAL(7,2) comment ‘工资月薪’,
comm DECIMAL(7,2) comment ‘奖金’,
deptno INT(2) zerofill comment ‘部门编号’
);
创建薪资等级表
drop table if exists salgrade;
create table if not exists salgrade
(
grade INT comment ‘等级’,
losal INT comment ‘此等级最低工资’,
hisal INT comment ‘此等级最高工资’
);
插入部门数据
insert into dept (deptno, dname, loc) values (10, ‘ACCOUNTING’, ‘NEW YORK’);
insert into dept (deptno, dname, loc) values (20, ‘RESEARCH’, ‘DALLAS’);
insert into dept (deptno, dname, loc) values (30, ‘SALES’, ‘CHICAGO’);
insert into dept (deptno, dname, loc) values (40, ‘OPERATIONS’, ‘BOSTON’);
插入雇员数据
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7369, ‘SMITH’, ‘CLERK’, 7902, ‘1980-12-17’, 800, null, 20);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7499, ‘ALLEN’, ‘SALESMAN’, 7698, ‘1981-02-20’, 1600, 300, 30);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7521, ‘WARD’, ‘SALESMAN’, 7698, ‘1981-02-22’, 1250, 500, 30);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7566, ‘JONES’, ‘MANAGER’, 7839, ‘1981-04-02’, 2975, null, 20);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7654, ‘MARTIN’, ‘SALESMAN’, 7698, ‘1981-09-28’, 1250, 1400, 30);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7698, ‘BLAKE’, ‘MANAGER’, 7839, ‘1981-05-01’, 2850, null, 30);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7782, ‘CLARK’, ‘MANAGER’, 7839, ‘1981-06-09’, 2450, null, 10);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7788, ‘SCOTT’, ‘ANALYST’, 7566, ‘1987-04-19’, 3000, null, 20);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7839, ‘KING’, ‘PRESIDENT’, null, ‘1981-11-17’, 5000, null, 10);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7844, ‘TURNER’, ‘SALESMAN’, 7698,’1981-09-08’, 1500, 0, 30);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7876, ‘ADAMS’, ‘CLERK’, 7788, ‘1987-05-23’, 1100, null, 20);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7900, ‘JAMES’, ‘CLERK’, 7698, ‘1981-12-03’, 950, null, 30);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7902, ‘FORD’, ‘ANALYST’, 7566, ‘1981-12-03’, 3000, null, 20);
insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7934, ‘MILLER’, ‘CLERK’, 7782, ‘1982-01-23’, 1300, null, 10);
插入薪资等级数据
insert into salgrade (grade, losal, hisal) values (1, 700, 1200);
insert into salgrade (grade, losal, hisal) values (2, 1201, 1400);
insert into salgrade (grade, losal, hisal) values (3, 1401, 2000);
insert into salgrade (grade, losal, hisal) values (4, 2001, 3000);
insert into salgrade (grade, losal, hisal) values (5, 3001, 9999);
单表查询
先将前面的基本查询进行一下复习:
1、工资大于500或者岗位为Manager的雇员,同时满足他们姓名为首字母大写J;
select ename,sal,deptno
from emp where sal>500 or job=’manager’ and ename like ‘J%’;
2、按照部门编号升序而雇员工资降序排序(order by)
select *from emp
order by deptno,sal desc;
3、使用年薪排序
select ename,sal*12+ifnull(comm,0) as ‘年薪’ from emp order by ‘年薪’;
4、按照empno升序排序,每页只显示3条记录,显示第一页。
select *from emp
order by empno
limit 0,3;
5、显示工资最高的员工姓名和工作岗位
select ename,job
from emp
where sal=(select max(sal) from emp);
6、显示工资高于平均工资的员工信息(ename,job,sal0
select ename,job,sal
from emp
where sal>(select avg(sal) from emp);
7、显示每个部门的平均工资和最高工资
(1)select deptno, format(avg(sal), 2) , max(sal) from EMP group by deptno;
(2)select deptno,avg(sal) as ‘平均工资’,max(sal) as ‘最高工资’ from emp group by deptno;
多表查询
为什么需要多表查询呢?
比如我们要求显示雇员名、雇员工资以及所在部门的名字,因为上面的数据来自EMP和DEPT表,因此要联合查询:
select *from emp,dept;
但是这样查询的数据是按笛卡尔积输出的,我们完全不需要这么多的数据。
练习:
1、查询雇员名、工资以及所在部门的名字
select ename sal,dname
from emp,dept where emp.deptno=dept.deptno;
2、显示部门编号为10的部门名,员工名和他的工资
select ename, sal,dname from EMP, DEPT where EMP.deptno=DEPT.deptno and DEPT.deptno = 10;
自连接
自连接是指在同一张表连接查询
1、显示员工FORD的上级领导的姓名
(1)单表查询:
select ename from emp
where empno=(select mgr from emp where ename=’FORD’);
(2)多表查询
select leader.ename
from emp worker,emp leader
where worker.mgr=leader.empno
and worker.ename=’FORD’;
子查询
子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询
单行子查询:结果只有一行
1、显示SMITH同一部门的员工信息(ename,job,sal);
select ename,job,sal
from emp
where deptno=(select deptno from emp where ename=’smith’);
多行子查询(in all any):返回多条记录的子查询
使用关键字in
1、查询和10号部门工作相同的ename,job,sal,deptno,但是不包含10号部门自己;
select ename,job,sal,deptno
from emp
where job in(select job from emp where deptno=10)
and deptno<>10;
使用关键字all
2、显示工资比部门编号为30的所有员工的工资高的员工的姓名、工资和部门号
select ename,sal,deptno from emp
where sal > all(select sal from emp where deptno=30);
//where sal > (select max(sal) from emp where deptno=30);
使用关键字any
3、显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号
select ename,sal,deptno from emp
where sal > any(select sal from emp where deptno=30);
多列子查询
查询返回多个列数据的子查询语句
1、查询和SMITH的部门和岗位完全相同的所有雇员信息,不含SMITH本人
select ename,job,sal from emp
where (deptno,job)=(select deptno,job from emp where ename = ‘smith’)
and ename <> ‘smith’;
多表子查询
子查询当做临时表
1、如何显示高于自己部门平均工资的员工的信息
获取各个部门的平均工资,将其看作临时表tmp
select ename,job,sal
from emp,
(select avg(sal) as avg_sal,deptno from emp group by deptno) as tmp
where emp.deptno = tmp.deptno
and sal > tmp.avg_sal;
2、查找每个部门工资高的人的ename,job,sal
select ename,job,sal from emp,
(select max(sal) as max_sal,deptno from EMP group by deptno) as tmp
where EMP.deptno=tmp.deptno and sal=tmp.max_sal;
3、显示每个部门的信息(部门名,编号,地址)和人员数量。
//多表查询
select dname,dept.deptno,loc,count(*) as “人员数量”
from emp,dept
where emp.deptno=dept.deptno
group by deptno;
//使用子查询
(1)对EMP表进行人员统计
select count(*), deptno from EMP group by deptno;
(2) 将上面的表看作临时表
select DEPT.deptno, dname, mycnt, loc from DEPT,
(select count(*) mycnt, deptno from EMP group by deptno) tmp
where DEPT.deptno=tmp.deptno;
自我复制
上面使用了多表和子查询两种方式进行查询,到底哪个效率高呢?我们需要弄大量数据来进行测试。可以使用自我复制创建海量数据。
举例如下:
1、create table temp like emp; //复制表结构
2、insert into temp select *from emp; //将emp中的数复制到temp
3、insert into temp select *from temp; //自我复制,…..直到表有20多万
…..直到表有20多万
from子查询效率高于多表查询
删除表的重复记录
我们先建一个有重复数据的表:
插入数据:
共需要4步:
1、创建空表使得结构与原表相同
2、导入不重复数据
3、把原表删除
drop table t1;
4、将新表改为原表
查看表,成功:
合并查询
在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union,union all
查找工资大于2500和职位为Manager的人(enamel,sal,job)
1、union(用于取得两个结果集的并集,并且会自动去掉结果集中重复行)
select ename,job,sal from emp where sal > 2500
union
select ename,job,sal from emp where job = ‘manager’;
2、union all(该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行)
select ename,job,sal from emp where sal > 2500
union all
select ename,job,sal from emp where job = ‘manager’;
外键(消除冗余)
- 外键用于定义主表和从表之间的关系;
- 外键约束主要定义在从表上,主表则必须是有主键约束或unique约束;
-
当定义外键后,要求外键列数据必须在主表的主键列存在或为null。
语法如下:
foreign key(字段名) references 主表(列)
eg:创建主表
再创建从表
正常插入数据
注意:可以让班级id为null,比如来了一个学生,目前还没有分配班级。
不能插入一个班级号不存在的学生,因为没有这个班级,所以插入不成功。