MySQL基础(四)——数据查询语言DQL(三)之多表查询

前言

  我们上篇文章给大家介绍了表查询的一些实例,这些实例均是企业面试的真题,来自牛客网。其实MySQL重在实践,语法很固定,不像算法题要有一定的思路,但是MySQL把题目要查的查出来就够了,因此要多加练习就好。本文给大家介绍多表连接查询以及嵌套查询。首先给大家讲介绍多表查询。

一、多表查询

  我们在MySQL中有单表查询也有多表查询。在多表查询中,通过不同表中具有相同意义的关键字段,将多个表进行连接,查询不同表中的字段信息。我们的连接方式一般有 内连接和外连接,也就是经常提到的左连接和右连接。一般来说,多表连接的结果通过以下三个属性决定:

  • 方向性:在外连接中写在前边的表为左表、写在后边的表为右表
  • 主附关系:主表要出所有的数据范围,附表与主表无匹配项时标记为null,内连接时无主附表之分
  • 对应关系:关键字段中有重复值的表为多表,没有重复值的表为一表

  其实,我们在进行多表连接的时候,其实无论是左连接还是右连接,最关键的是多张表中确定哪张表作为主表,如果是做左连接则主表在前面,如果用右连接则是在右面。我们在连接的时候分为一对一、一对多以及多对多模式,其中的模式如下:



  我们为什么要进行对表拆分呢?其实为了节省存储空间,避免数据冗余。如果所有数据全部放在一张表里则是如下:

  首先,我们介绍内连接。按照连接条件合并两个表,返回满足条件的行。具体格式如下:select 字段1[,…] from 表1[ inner] join 表2 on 表1.key=表2.key;。其用数学中的集合表示如下:

  在表中查询出来体现的是如下:

  接下来,我们介绍左连接。结果中除了包括满足连接条件的行外,还包括左表的所有行。具体格式如下:select 字段1[,…] from 表1 left join 表2 on 表1.key=表2.key;。其用数学中的集合表示如下:

  在表中查询出来体现的是如下:

  最后,我们介绍右连接。结果中除了包括满足连接条件的行外,还包括右表的所有行。具体格式如下:select 字段1[,…] from 表1 right join 表2 on 表1.key=表2.key;。其用数学中的集合表示如下:

  在表中查询出来体现的是如下:

  除了这三种查询之外,我们还可以联合查询。就是把多条select语句的查询结果合并为一个结果集。被合并的结果集的列数、顺序和数据类型必须完全一致

  union去重select 字段1[,字段2,…] from 表名 union select 字段1[,字段2,…] from 表名;
  union all不去重select 字段1[,字段2,…] from 表名 union all select 字段1[,字段2,…] from 表名;

  具体的查询结果如下:

二、多表查询连接案例

  我们首先创建表t1t2,具体命令如下:

create table t1(key1 char,v1 int);
create table t2(key2 char,v2 int);

  其次,我们给t1、t2表插入一些数据,执行如下:

insert into t1 values('a',1),('a',2),('b',3),('c',4),('a',13);                    
insert into t2 values('b',10),('b',11),('a',12),('a',13),('e',14);

  插入数据之后,我们查看t1、t2表;

select * from t1;
select * from t2;

  执行的代码效果如下:

  我们接下来对这两张表进行内连接;命令如下:

select * from t1 inner join t2 on t1.key1 = t2.key2;
select * from t1  join t2 on t1.key1 = t2.key2;

  两条命令执行结果如下:

  我们接下来将两张表进行左连接,命令如下:

select * from t1 left join t2 on t1.key1 = t2.key2;

  两条命令执行结果如下:

  接下来给大家将两张表进行右连接;MySQL语句如下:

select * from t1 right join t2 on t1.key1 = t2.key2;

  两条命令执行结果如下:

  最后介绍合并查询,具体语句如下:

select * from t1 union select * from t2;

  命令执行结果如下:

  我们发现合并后,数据库自动去重了,如果不去重的话,我们可以用union all,具体实现如下:

select * from t1 union all select * from t2;

  命令执行结果如下:

  我们在举几个多表连接的案例,我们首先创建salgrade表;具体语句如下:

create table salgrade(grade int,losal int,hisal int);

  插入相应的数据如下:

insert into salgrade values (1,700,1200),(2,1201,1400),(3,1401,2000),(4,2001,3000),(5,3001,9999);

  我们查看刚才创建的salgrade表:

select * from salgrade;

  命令执行结果如下:

  查询每位员工的ename,dname,sal,由于我们查的是每位员工的相关信息;因此,我们以emp表为主,这里我们提到的emp表和dept表是我们之前的文章有数据,练习的读者可以看此文章。具体实现如下:

select empname,dname,sal
from emp left join dept on emp.deptno = dept.deptno;

  命令执行结果如下:

  查询各地区的员工数,具体实现代码如下:

select loc,count(empno) 员工数
from emp left join dept on  emp.deptno = dept.deptno
group by loc;

  命令执行结果如下:

  查询manager的姓名、所属部门名称和入职日ename,dname,job,hiredate(内连接/笛卡尔积连接),具体命令如下:

select empname,dname,job,hiredate
from emp inner join dept on emp.deptno=dept.deptno
where job='manager';

  命令执行结果如下:

  接下来用笛卡尔积实现:

select empname,dname,job,hiredate
from emp,dept
where emp.deptno=dept.deptno and job='manager';

  命令执行结果如下:

  查询每位员工的工资等级;empno,ename,sal,grade(不等值连接),具体实现如下:

select empno,empname,sal,grade
from emp left join salgrade on sal between losal and hisal;

  命令执行结果如下:

  查询每个工资等级的员工数,具体实现如下:

select grade,count(empno) 员工数
from salgrade left join emp on sal between losal and hisal
group by grade;

  命令执行结果如下:

  查询所有员工姓名及其直属领导姓名(自连接:通过别名,将同一张表视为多张表),具体实现如下:

select e.empname 员工姓名, l.empname 领导姓名
from emp l left join emp e on l.mgr = e.empno;

  命令执行结果如下:

  查询入职日期早于其直属领导的员工:empno,ename,dname,具体实现如下 :

select e.empno,e.empname,dname
from emp e 
left join emp l on e.mgr = l.empno 
left join dept on e.deptno = dept.deptno
where e.hiredate < l.hiredate;

  命令执行结果如下:

三、子查询

  我们介绍子查询,其实子查询和多表连接是差不多的,并且从昨天的练习题目中不难发现:只要用到多表连接就能用到子查询代替。子查询是一个select语句中包含另一个或多个完整的select语句。子查询出现的位置有两种:出现在where子句中,即:将子查询返回的结果作为主查询的条件,另一种则是出现在from子句中,也就是将子查询返回的结果作为主查询的一个表。子查询的分类主要如下:

  • 标量子查询:返回的结果是一个数据(单行单列)
  • 行子查询:返回的结果是一行(单行多列)
  • 列子查询:返回的结果是一列(多行单列)
  • 表子查询:返回的结果是一张临时表(多行多列)

  我们子查询的操作符如下:

四、子查询案例分析

  我们先介绍标量子查询的案例;查询基本工资高于公司平均工资的员工信息,具体用sql语句实现如下:

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

  命令执行结果如下:

  查询和allen同一个领导的员工:empno,ename,job,mgr,具体实现如下:

select empno,empname,job,mgr
from emp
where mgr=(select mgr from emp where empname = 'allen') and empname <> 'allen';

  命令执行结果如下:

  接下来,我们列举行子查询的案例。查询和smith同部门同职位的员工:empno,ename,job,deptno,具体实现如下:

select empno,empname,job,deptno
from emp 
where (deptno, job) = (select deptno, job from emp where empname = 'smith') and empname <> 'smith';

  命令执行结果如下:
  另外,我们列举列子查询的案例。查询普通员工的工资等级:empno,ename,sal,grade,具体实现如下:

select empno,empname,sal,grade
from emp left join salgrade on sal between losal and hisal
where empno not in (select distinct mgr from emp where mgr is not null);

  命令执行结果如下:

  查询员工数不少于5人的部门的所有员工:empno,ename,deptno:,具体实现如下:

select empno,empname,deptno
from emp
where deptno in (select deptno from emp group by deptno having count(empno)>=5);

  命令执行结果如下:

  查询基本工资高于30号部门任意员工的员工信息,具体实现如下:

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

select *
from emp
where sal > (select min(sal) from emp where deptno = 30) and deptno <> 30;

  命令执行结果如下:

  查询基本工资高于30号部门所有员工的员工信息,具体实现如下:

select * 
from emp
where sal > all(select sal from emp where deptno = 30) and deptno <> 30;

select *
from emp
where sal > (select max(sal) from emp where deptno = 30) and deptno <> 30;

  命令执行结果如下:

  最后,我们介绍from子查询的案例,查询各部门最高工资的员工:empno,ename,sal,deptno,具体实现如下:

select empno,empname,sal,emp.deptno
from emp
left join (select deptno,max(sal) 最高工资 from emp group by deptno) t on emp.deptno = t.deptno
where sal = 最高工资;

  命令执行结果如下:

总结

  我们上篇文章给大家介绍了表查询的一些实例,这些实例均是企业面试的真题,来自牛客网。其实MySQL重在实践,语法很固定,不像算法题要有一定的思路,但是MySQL把题目要查的查出来就够了,因此要多加练习就好。本文给大家介绍了多表连接查询以及嵌套查询,包括内连接和外连接,也介绍了子查询,包括in以及any等关键字的用法。最后分别通过案例将这部分进行讲解,为了让大家对所介绍的知识点进行更好的应用。因此,mysql是很重要的一个技能,几乎计算机中的每个岗位都需要一个mysq技能,因此,需要我们特别的掌握。生命不息,奋斗不止,我们每天努力,好好学习,不断提高自己的能力,相信自己一定会学有所获。加油!!!

猜你喜欢

转载自blog.csdn.net/Oliverfly1/article/details/115049542