Mysql----关联查询

测试表

dept表

创建dept表:

DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (
`deptno` int(2) NOT NULL,
`dname` varchar(14) DEFAULT NULL,
`loc` varchar(13) DEFAULT NULL,
PRIMARY KEY (`deptno`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

插入数据:

INSERT INTO `dept` VALUES ('10', 'ACCOUNTING', 'NEW YORK');
INSERT INTO `dept` VALUES ('20', 'RESEARCH', 'DALLAS');
INSERT INTO `dept` VALUES ('30', 'SALES', 'CHICAGO');
INSERT INTO `dept` VALUES ('40', 'OPERATIONS', 'BOSTON');

在这里插入图片描述

emp表

创建emp表:

DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
`empno` int(4) NOT NULL,
`ename` varchar(10),
`job` varchar(9),
`mgr` int(4),
`hiredate` date,
`sal` int(7),
`comm` int(7),
`deptno` int(2),
PRIMARY KEY (`empno`),
KEY `fk_deptno` (`deptno`),
CONSTRAINT `fk_deptno` FOREIGN KEY (`deptno`) REFERENCES `dept` (`deptno`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

插入数据:

INSERT INTO `emp` VALUES ('7369', 'SMITH', 'CLERK', '7902', '1980-12-17', '800', null, '20');
INSERT INTO `emp` VALUES ('7499', 'ALLEN', 'SALESMAN', '7698', '1981-02-20', '1600', '300', '30');
INSERT INTO `emp` VALUES ('7521', 'WARD', 'SALESMAN', '7698', '1981-02-22', '1250', '500', '30');
INSERT INTO `emp` VALUES ('7566', 'JONES', 'MANAGER', '7839', '1981-04-02', '2975', null, '20');
INSERT INTO `emp` VALUES ('7654', 'MARTIN', 'SALESMAN', '7698', '1981-09-28', '1250', '1400', '30');
INSERT INTO `emp` VALUES ('7698', 'BLAKE', 'MANAGER', '7839', '1981-05-01', '2850', null, '30');
INSERT INTO `emp` VALUES ('7782', 'CLARK', 'MANAGER', '7839', '1981-06-09', '2450', null, '10');
INSERT INTO `emp` VALUES ('7788', 'SCOTT', 'ANALYST', '7566', '1987-04-19', '3000', null, '20');
INSERT INTO `emp` VALUES ('7839', 'KING', 'PRESIDENT', null, '1981-11-17', '5000', null, '10');
INSERT INTO `emp` VALUES ('7844', 'TURNER', 'SALESMAN','7698', '1981-09-08', '1500', '0', '30');
INSERT INTO `emp` VALUES ('7876', 'ADAMS', 'CLERK', '7788', '1987-05-23', '1100', null, '20');
INSERT INTO `emp` VALUES ('7900', 'JAMES', 'CLERK', '7698', '1981-12-03', '950', null, '30');
INSERT INTO `emp` VALUES ('7902', 'FORD', 'ANALYST', '7566', '1981-12-03', '3000', null, '20');
INSERT INTO `emp` VALUES ('7934', 'MILLER', 'CLERK', '7782', '1982-01-23', '1300', null, '10');
INSERT INTO `emp` VALUES ('8002', 'IRONMAN', 'MANAGER', '7839', '1981-06-09', '1600', null, '10');
INSERT INTO `emp` VALUES ('8003', 'SUPERMAN', 'MANAGER', '7839', '1981-06-09', '1600', null, null);

在这里插入图片描述

1、笛卡尔积

在做多张表查询时,我们使用某一张表中的每一条记录都与另外一张表的所有记录进行组合。比如表A有x条记录,表B有y条记录,最终组合数为x*y,这个值就是笛卡尔积,通常没有意义。

示例

select * from emp,dept;

则一共有16*4=64条记录

2、等值连接

在做多张表查询时,这些表中会存在着有关联的两个字段。使用某一张表中的一条记录的一个字段与另外一张表中的相关字段进行匹配,组合成一条新记录。使用"="连接关联字段

示例
显示员工的信息以及该员工所属部门的信息:

SELECT * FROM emp e,dept d where e.deptno=d.deptno;

在这里插入图片描述

3、内连接

内连接返回所有满足条件的记录,查询效果与等值连接一样。
关键字:join on
用法:表A [inner] join 表B on 关联条件

示例
显示员工的信息以及该员工所属部门的信息:

SELECT * FROM emp e join dept d on e.deptno=d.deptno;

在这里插入图片描述

4、外连接

在做关联查询时,我们所需要的数据,除了找到那些满足关联条件的数据外,有时候还需要不满足关联条件的数据。此时则需要使用外连接。

会涉及到两个概念:

  • 驱动表(主表):除了显示满足条件的数据,还需要显示不满足条件的数据的表
  • 从表(副表):只显示满足关联条件的数据的表

注意:mysql外连接只支持左外连接,右外连接,不支持全外连接

  1. 左外连接:
    表A left [outer] join 表B on 关联条件。
    表A是驱动表,表B是从表
  2. 右外连接:
    表A right [outer] join 表B on 关联条件
    表B是驱动表,表A是从表
  3. 全外连接:
    两张表的数据不管满不满足条件,都做显示。
    表A full [outer] join 表B on 关联条件

示例
左外连接:

SELECT * FROM emp e left join dept d on e.deptno=d.deptno;

此时:
emp是驱动表,dept是从表

在这里插入图片描述

右外连接:

SELECT * FROM emp e right join dept d on e.deptno=d.deptno;
此时:
dept是驱动表,emp是从表

在这里插入图片描述

5、自连接

自连接是一种特殊的关联查询。数据的来源是同一个表,这样的表内的多个字段要存有关系。我们要使用表别名来虚拟出两个表。

示例
查询员工编号、姓名、职位及其上司的编号、姓名、职位:

SELECT e1.empno,e1.ename,e1.job,e1.mgr,e2.ename,e2.job FROM emp e1,emp e2 where e1.mgr=e2.empno;

上述语句不够严谨,当员工没有上司时候,则不显示(因此,通常做查询时,需要注意数据,并决定是否使用外连接)

SELECT e1.empno,e1.ename,e1.job,e1.mgr,e2.ename,e2.job 
FROM emp e1 
left join 
emp e2 
on e1.mgr=e2.empno;

在这里插入图片描述

查询(所有)员工编号、姓名、职位及其下属的编号、姓名、职位:

下列语句只能查询出有下属的员工的信息,没有下属的员工,则无法显示(即下列语句会丢数据)
SELECT e1.empno,e1.ename,e1.job,e2.empno,e2.ename,e2.job FROM emp e1,emp e2 where e1.empno=e2.mgr;

严谨:
SELECT e1.empno,e1.ename,e1.job,e2.empno,e2.ename,e2.job  
FROM emp e1 
left join 
emp e2 
on e1.empno=e2.mgr;


在这里插入图片描述

6、高级关联查询

有时候,我们要查询的数据,一个简单的查询语句完成不了。并且,我们使用的数据,表中不能直观体现出来,而是预先经过一次查询才会有所体现。那么先执行的查询,我们称之子查询。被子查询嵌入的查询语句称之为父查询或主查询。

子查询返回的数据特点:

  • 可能是单行单列的数据。
  • 可能是多行单列的数据
  • 可能是单行多列的数据
  • 可能是多行多列的数据

子查询所在的位置:

  • 子查询可以在where子句中
  • 子查询可以在from子句中
  • 子查询可以在having子句中
  • 子查询可以在select字句中,相当于外连接的另外一种写法

1、子查询在where子句中

查询FORD的上司信息

select * from emp where empno = (select mgr FROM emp where ename='FORD');

查询工资大于JONES工资的所有员工姓名,职位,工资

select ename,job,sal from emp where sal>(select sal FROM emp where ename='JONES');

查询部门’SALES’里的所有员工的信息

select * from emp where deptno=(select deptno FROM dept where dname='SALES');

查询和员工姓名SCOTT同职位的员工信息

select * from emp where job=(select job FROM emp where ename='SCOTT');

查询薪水比所有员工的平均薪水高的员工信息

select * from emp where sal>(select avg(ifnull(sal,0)) FROM emp);

查询出部门中的人职位有SALESMAN但是自己职位不是SALESMAN的员工信息

select * from emp where deptno in (select distinct deptno FROM emp where job='SALESMAN') and job<>'SALESMAN';

查询有员工的部门信息

select deptno,dname,loc from dept d where exists (select * from emp e where d.deptno =e.deptno);

注意:
exists 关键字
有时候,子查询需要引用主查询的字段数据,我们使用exists关键字。exists后面的子查询至少返回一条记录,则整个条件为true;

2、子查询在from子句中

查询员工的姓名,工资,及其部门号,部门的平均工资和平均奖金,按照部门号升序

select ename,sal,e1.deptno,e2.avgsal,e2.avgcomm from emp e1 
left join 
(select deptno,avg(ifnull(sal,0)) avgsal,avg(ifnull(comm,0)) avgcomm from emp group by deptno)e2 
on 
e1.deptno=e2.deptno 
order by e1.deptno ;

注意:
需要用到左外连接(left join),且emp充当驱动表,否则,无法查出所有的员工信息

查询部门号,部门名称,地址,最高工资,总人数

select d.deptno,dname,loc,maxsal,sumpeople from dept d 
left join
(select deptno,max(sal) maxsal,count(*) sumpeople from emp group by deptno) e 
on 
d.deptno=e.deptno;

查询工资大于本部门平均工资的员工的姓名、工资、部门号、部门平均工资,按照部门号降序排序

select ename,sal,e1.deptno,avgsal from 
emp e1,
(select deptno,avg(ifnull(sal,0)) avgsal from emp group by deptno) e2 
where 
e1.deptno=e2.deptno 
and 
sal>avgsal 
order by e1.deptno desc;
 
	或
 
select ename,sal,e1.deptno,avgsal from emp e1 
join 
(select deptno,avg(ifnull(sal,0)) avgsal from emp group by deptno) e2 
on 
(e1.deptno=e2.deptno and sal>avgsal) 
order by e1.deptno desc;

3、子查询在having子句中

查询部门平均工资大于30号部门平均工资的部门号、平均工资

select deptno,avg(ifnull(sal,0)) avgsal from emp 
group by deptno 
having 
avgsal>(select avg(ifnull(sal,null)) avg30 from emp where deptno=30);

4、子查询在select子句中

查询员工编号,姓名,职位,和其上司编号,姓名,职位

select e1.empno,e1.ename,e1.job,
(select e2.empno  from emp e2 where e2.empno=e1.mgr)mgrno,
(select e3.ename  from emp e3 where e3.empno=e1.mgr)mgrname,
(select e4.job  from emp e4 where e4.empno=e1.mgr)mgrjob
 from emp e1

查询每个员工的姓名,工资,部门号,及其部门的平均工资、工资之和,按照部门号升序排序

select ename,sal,deptno,
(select avg(ifnull(sal,0)) from emp where deptno = e1.deptno group by deptno) avgsal,
(select sum(sal) from emp where deptno=e1.deptno group by deptno) sumsal 
from emp e1 order by deptno asc

参考

https://blog.youkuaiyun.com/Michael__One/article/details/84870766
https://blog.youkuaiyun.com/qq_39192827/article/details/84404353

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值