天天看点

Select之多表查询

前面我们讲解的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%’;

Select之多表查询

2、按照部门编号升序而雇员工资降序排序(order by)

select *from emp

order by deptno,sal desc;

Select之多表查询

3、使用年薪排序

select ename,sal*12+ifnull(comm,0) as ‘年薪’ from emp order by ‘年薪’;

Select之多表查询

4、按照empno升序排序,每页只显示3条记录,显示第一页。

select *from emp

order by empno

limit 0,3;

Select之多表查询

5、显示工资最高的员工姓名和工作岗位

select ename,job

from emp

where sal=(select max(sal) from emp);

Select之多表查询

6、显示工资高于平均工资的员工信息(ename,job,sal0

select ename,job,sal

from emp

where sal>(select avg(sal) from emp);

Select之多表查询

7、显示每个部门的平均工资和最高工资

(1)select deptno, format(avg(sal), 2) , max(sal) from EMP group by deptno;

Select之多表查询

(2)select deptno,avg(sal) as ‘平均工资’,max(sal) as ‘最高工资’ from emp group by deptno;

Select之多表查询

多表查询

为什么需要多表查询呢?

比如我们要求显示雇员名、雇员工资以及所在部门的名字,因为上面的数据来自EMP和DEPT表,因此要联合查询:

select *from emp,dept;

但是这样查询的数据是按笛卡尔积输出的,我们完全不需要这么多的数据。

练习:

1、查询雇员名、工资以及所在部门的名字

select ename sal,dname

from emp,dept where emp.deptno=dept.deptno;

Select之多表查询

2、显示部门编号为10的部门名,员工名和他的工资

select ename, sal,dname from EMP, DEPT where EMP.deptno=DEPT.deptno and DEPT.deptno = 10;

Select之多表查询

自连接

自连接是指在同一张表连接查询

1、显示员工FORD的上级领导的姓名

(1)单表查询:

select ename from emp

where empno=(select mgr from emp where ename=’FORD’);

Select之多表查询

(2)多表查询

select leader.ename

from emp worker,emp leader

where worker.mgr=leader.empno

and worker.ename=’FORD’;

Select之多表查询

子查询

子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询

单行子查询:结果只有一行

1、显示SMITH同一部门的员工信息(ename,job,sal);

select ename,job,sal

from emp

where deptno=(select deptno from emp where ename=’smith’);

Select之多表查询

多行子查询(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;

Select之多表查询

使用关键字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);

Select之多表查询

使用关键字any

3、显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号

select ename,sal,deptno from emp

where sal > any(select sal from emp where deptno=30);

Select之多表查询

多列子查询

查询返回多个列数据的子查询语句

1、查询和SMITH的部门和岗位完全相同的所有雇员信息,不含SMITH本人

select ename,job,sal from emp

where (deptno,job)=(select deptno,job from emp where ename = ‘smith’)

and ename <> ‘smith’;

Select之多表查询

多表子查询

子查询当做临时表

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;

Select之多表查询

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;

Select之多表查询

3、显示每个部门的信息(部门名,编号,地址)和人员数量。

//多表查询

select dname,dept.deptno,loc,count(*) as “人员数量”

from emp,dept

where emp.deptno=dept.deptno

group by deptno;

Select之多表查询

//使用子查询

(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;

Select之多表查询

自我复制

上面使用了多表和子查询两种方式进行查询,到底哪个效率高呢?我们需要弄大量数据来进行测试。可以使用自我复制创建海量数据。

举例如下:

1、create table temp like emp; //复制表结构

2、insert into temp select *from emp; //将emp中的数复制到temp

3、insert into temp select *from temp; //自我复制,…..直到表有20多万

Select之多表查询

…..直到表有20多万

from子查询效率高于多表查询

删除表的重复记录

我们先建一个有重复数据的表:

Select之多表查询

插入数据:

Select之多表查询

共需要4步:

1、创建空表使得结构与原表相同

Select之多表查询

2、导入不重复数据

Select之多表查询

3、把原表删除

drop table t1;

4、将新表改为原表

Select之多表查询

查看表,成功:

Select之多表查询

合并查询

在实际应用中,为了合并多个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’;

Select之多表查询

2、union all(该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行)

select ename,job,sal from emp where sal > 2500

union all

select ename,job,sal from emp where job = ‘manager’;

外键(消除冗余)

  1. 外键用于定义主表和从表之间的关系;
  2. 外键约束主要定义在从表上,主表则必须是有主键约束或unique约束;
  3. 当定义外键后,要求外键列数据必须在主表的主键列存在或为null。

    语法如下:

    foreign key(字段名) references 主表(列)

    eg:创建主表

    再创建从表

    正常插入数据

    注意:可以让班级id为null,比如来了一个学生,目前还没有分配班级。

    不能插入一个班级号不存在的学生,因为没有这个班级,所以插入不成功。