当前位置: 首页 > news >正文

『 数据库 』MySQL复习 - 查询进阶指南:基于经典测试表的复合查询实践

文章目录

    • 1 例表
    • 2 基本查询回顾
      • 2.1 查询工资高于500或岗位为MANAGER的雇员, 同时还要满足他们的姓名首写为J
      • 2.2 按照部门号升序而雇员工资降序
      • 2.3 按照年薪进行降序排序
      • 2.4 显示工资最高的员工名字和工作岗位 (子查询)
      • 2.5 显示工资高于平均工资的员工信息
      • 2.7 显示每个部门的平均工资和最高工资
      • 2.8 显示平均工资低于 2000 的部门号和它的平均工资
      • 2.9 显示每种岗位的雇员总数和平均工资
    • 3 多表查询
      • 3.1 多表笛卡尔积
      • 3.2 显示雇员名, 雇员工资以及所在部门的名字
      • 3.3 显示部门号为10的部门名, 雇员名与薪资
      • 3.4 显示各个员工的姓名, 薪资以及薪资级别
      • 3.5 自连接
    • 4 子查询
      • 4.1 单行子查询
      • 4.2 多行子查询
      • 4.3 多列子查询
      • 4.4 在 from 子句中使用的子查询
        • 4.4.1 显示每个高于自己部门平均工资的姓名, 部门, 工资, 平均工资
        • 4.4.2 查找每个部门工资最高的人的姓名, 工资, 部门以及最高工资
        • 4.4.3 显示每个部门的信息 (部门名, 编号, 地址)和人员数量
      • 4.5 合并查询
        • 4.5.1 UNION 关键字
        • 4.5.2 UNION ALL 关键字
    • 5 表的内外连接
      • 5.1 内连接
      • 5.2 外连接
        • 5.2.1 左外连接
        • 5.2.2 右外连接
        • 5.2.3 练习
    • 6 总结

1 例表

该章节所需表表为如下:

  • oracle9i经典测试用表

三张表的内容分别为如下:

  • emp

  • dept

  • salgrade


2 基本查询回顾

复合查询前回顾基本查询内容, 以为符合查询进行对应的准备;


2.1 查询工资高于500或岗位为MANAGER的雇员, 同时还要满足他们的姓名首写为J

这里分为几个条件:

  1. 查询工资高于500或岗位为MANAGER
  2. 上述条件满足后需要找到姓名首写字母为大写的J

那么这样的条件就是1 AND 2(即SELECT ... FROM ... WHERE (工资高于500 OR 岗位为MANAGER) AND 姓名首写为 J );

所需的表为emp表, 其SQL语句为:

select ename, sal, job from emp where (sal>500 or job='MANAGER') and (ename like "J%");

结果为:

也可以使用内置函数:

select * from emp where (sal>500 or job="MANAGER") and substring(ename, 1, 1)='J';

结果为:


2.2 按照部门号升序而雇员工资降序

这里的两个条件都是ORDER BY条件:

  • 首要排序规则

    部门号升序;

  • 次要排序规则

    雇员工资降序

对应的SQL语句即为:

select * from emp order by deptno asc, sal desc;

结果为:


2.3 按照年薪进行降序排序

年薪即为sal * 12 + comm;

但是在emp表中的comm列存在很多NULL值, 而与NULL值进行计算的结果都为NULL;

mysql> select 100+NULL;
+----------+
| 100+NULL |
+----------+
|     NULL |
+----------+
1 row in set (0.00 sec)

因此此处除了加上comm以外还需要将NULL排除;

可以采用IFNULL()函数来进行判断;

因此SQL语句为:

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

结果为:


2.4 显示工资最高的员工名字和工作岗位 (子查询)

这一题的解法可以采用order by降序的方式对sal进行排序, 首行即为工资最高的员工, 此时使用limit 1, 1取其名字与岗位即可;

对应的SQL语句为:

select ename, sal, job from emp order by sal desc limit 0 ,1;

select ename, sal, job from emp order by sal desc limit 1;

对应的结果为:

而实际上除了这种方式以外, 我们可以使用聚合函数MAX()来获取某一列的最大值, 但遗憾的是如果使用聚合函数来获取最大值, 对应的就不能将另外两列(姓名, 岗位)展现出来;

因此可以将这个语句变为两个步骤:

  1. 通过聚合函数找到最高的工资

    mysql> select max(sal) from emp;
    +----------+
    | max(sal) |
    +----------+
    |  5000.00 |
    +----------+
    1 row in set (0.00 sec)
    
  2. 找到通过最高的工资找到对应记录的姓名, 工资以及岗位

    mysql> select ename, sal, job from emp where sal=5000;
    +-------+---------+-----------+
    | ename | sal     | job       |
    +-------+---------+-----------+
    | KING  | 5000.00 | PRESIDENT |
    +-------+---------+-----------+
    1 row in set (0.00 sec)
    

而在MySQL中支持一种子查询的查询方式, 即为一条查询语句中可以嵌套另一条查询语句, 以此进行更为精确的查询;

对应的SQL语句为:

select ename, sal, job from emp where sal=(select max(sal) from emp);

对应的查询结果为:


2.5 显示工资高于平均工资的员工信息

2.4 相同, 只不过where条件由 = 变为 > ;

对应的查询语句为:

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

结果为:


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

这里要求是每个部门, 因此需要用GROUP BY对部门进行分组, 而后通过聚合函数AVG()MAX()来聚合对应的结果(工资);

对应SQL语句为:

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

结果为:


2.8 显示平均工资低于 2000 的部门号和它的平均工资

这一个查询可以将问题拆成几个部分:

  1. 查询所有部门的平均工资

    这里需要查到所有部门的平均工资也意味着需要使用GROUP BYdeptno进行分组;

    而后再使用avg()函数来找到他的平均工资;

    mysql> select deptno, avg(sal) 平均工资 from emp group by deptno;
    +--------+--------------+
    | deptno | 平均工资     |
    +--------+--------------+
    |     20 |  2175.000000 |
    |     30 |  1566.666667 |
    |     10 |  2916.666667 |
    +--------+--------------+
    3 rows in set (0.00 sec)
    
  2. 找到平均工资<2000的部门号和它的平均工资

    而后后加条件是查询平均工资少于2000的记录, 而此处无法使用where语句对聚合函数的结果与别名进行展示, 因此需要使用HAVING语句对聚合的结果进行追加条件;

因此最终的SQL语句为:

select deptno, avg(sal) 平均工资 from emp group by deptno having 平均工资 < 2000;

结果为:


2.9 显示每种岗位的雇员总数和平均工资

这个与2.8相差无异, 主要是使用group by对岗位进行分组, 而后使用聚合函数COUNT()AVG()分别对雇员数量和工资进行聚合;

对应的SQL语句为:

select job 岗位, count(empno) 总数, avg(sal) 平均薪资 from emp group by job;

结果为:


3 多表查询

通常情况下, 为了高内聚低耦合, 所查询的记录不一定只在一张表中所体现, 而是在多张表中体现, 多表通过一些外键等其他的约束进行关联, 因此表的查询不仅仅需要单表查询, 更需要多表查询;

如在 Oracle 9i经典测试用表中, 不同的关键数据被存储在不同的表之中, 在emp表中只有部门的编号而没有部门的名字;

而部门的名字在dept表中;


3.1 多表笛卡尔积

所谓的多表笛卡尔积是两张即以上的表的记录进行整合;

如假设存在两张表:

  • table_A

    mysql> create table if not exists table_A(-> val varchar(5)-> );
    Query OK, 0 rows affected (0.03 sec)mysql> insert into table_A values ('A1'), ('A2'), ('A3'), ('A4'), ('A5');
    Query OK, 5 rows affected (0.01 sec)
    Records: 5  Duplicates: 0  Warnings: 0mysql> select * from table_A;
    +------+
    | val  |
    +------+
    | A1   |
    | A2   |
    | A3   |
    | A4   |
    | A5   |
    +------+
    5 rows in set (0.00 sec)
    
  • table_B

    mysql> insert into table_B values ('B1'), ('B2'), ('B3'), ('B4'), ('B5');
    Query OK, 5 rows affected (0.01 sec)
    Records: 5  Duplicates: 0  Warnings: 0mysql> select * from table_B;
    +------+
    | val  |
    +------+
    | B1   |
    | B2   |
    | B3   |
    | B4   |
    | B5   |
    +------+
    5 rows in set (0.00 sec)
    

进行笛卡尔积的语句也很简单, 即from table_name的时候table_name有两张及以上的表即可以进行笛卡尔积;

即:

select * from table_A, table_B;

笛卡尔积会将所有有可能的记录进行穷举排列, 因此上述的查询语句执行结果将为:

可以看到table_A表的所有记录和table_B表的所有记录进行了穷举组合, 每张表的记录为5条, 因此这个笛卡尔积的记录为25条;

mysql> select count(*) from table_A, table_B;
+----------+
| count(*) |
+----------+
|       25 |
+----------+
1 row in set (0.00 sec)

3.2 显示雇员名, 雇员工资以及所在部门的名字

由于雇员名, 工资和所在部门的名字分别来自empdept两张表, 因此需要使用联合查询, 此处需要使用笛卡尔积;

对应的语句为:

select * from emp, dept;

对两张表进行笛卡尔积;

结果为:

而从结果可以看出, 实际上笛卡尔积的很多结果并不如我们所愿;

在笛卡尔积的结果中出现了很多无用的记录, 如结果中存在两个deptno, 而deptno20的记录与deptno40的记录明显为无用的记录, 因此需要使用where语句进行条件筛选;

两个表中存在的共同列为deptno, 因此笛卡尔积后有用的记录的SQL语句为:

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

结果为:

经过笛卡尔积与条件筛选后, 我们将两张表合并为了一张表, 此时重新回到题目, 可以看到我们可以对新整合出的一张表进行单表查询, 这就是笛卡尔积的最主要用法;

完整的SQL语句为:

select ename, sal, dname from emp, dept where emp.deptno=dept.deptno;

查询结果为:


3.3 显示部门号为10的部门名, 雇员名与薪资

这个问题也是相同, 步骤为:

  1. 两张表进行笛卡尔积并使用WHERE筛选出有效记录
  2. 将筛选出的有效记录作为一张表进行单表查询

对应的SQL语句为:

select ename, sal, dname from emp, dept where emp.deptno=dept.deptno and emp.deptno=10;

从这条SQL语句来看, 这一题只是增加了一个AND来并列其他条件;

查询结果为:


3.4 显示各个员工的姓名, 薪资以及薪资级别

其中姓名为emp表中的ename, 薪资为emp表中的sal, 薪资级别则属于为salgrade表中的grade;

这里同样对两张表进行笛卡尔积并筛选出有效数据;

其中笛卡尔积的SQL语句为:

 select * from emp, salgrade;

在这张表中, 需要筛选出有效的数据不能单纯依靠=来判断, 而是需要使用其他的条件判断, ><, 本质原因是两张表不存在相同的列名, 同时薪资的等级是依靠该薪资是否属于salgrade表中的[losal, hisal]范围;

因此笛卡尔积后进行筛选的SQL语句为:

select * from emp, salgrade where sal >= losal and sal <=hisal;

筛选后的结果为:

在查询到有效信息后对信息进行SELECT筛选出想要的列, 最终完整的SQL语句为:

select ename, sal, grade from emp, salgrade where sal >= losal and sal <=hisal;

筛选结果为:

除此之外还可以使用between语句, 对应的SQL语句为:

select ename, sal, grade from emp, salgrade where sal between losal and hisal;

查询结果同样为:


3.5 自连接

自连接同样是一种多表查询, 与一般的多表查询不同的是, MySQL支持一张表与该表自身进行笛卡尔积;

如:

select * from emp as t1, emp as t2;

在这里进行自连接时无法使用from emp, emp的方式进行自连接, 本质是当进行自连接时, 需要使用as对表进行重命名以防止出现两张表都使用类似emp.deptno的方式引发的歧义;

在使用自连接后对有效记录进行筛选, 对应的SQL语句为:

select * from emp as t1, emp as t2 where t1.ename=t2.ename;

最终的筛选结果为:

  • 通常什么时候需要使用自连接?

自连接的使用方式通常为, 查询单张表中的数据, 但其数据并不属于同一列的复合查询情况;

如举个例子:

  • 找出每个员工的领导

那么在这个例子下, 领导的编号为mgr, 而其名字不属于同一行的记录, 因此需要使用自连接;

首先需要表内进行自行的笛卡尔积, 即emp表的自连接;

select * from emp t1, emp t2;

而后使用where筛选无效记录的条件, 或者说筛选出有效的记录;

此处的有效记录为empnomgr, 因此需要使用t1.empno = t2.mgr;

对应的sql语句为:

select * from emp t1, emp t2 where t1.empno=t2.mgr;

结果为:

结果可以看出已经找出了每个员工的mgr;


4 子查询

MYSQL中支持一句SELECT语句中嵌套另一条SELECT语句;

如:

select * from (select * from table_name where [...]) where [...];

即将子查询的结果视为一张临时表, 随后对该临时表进行一个查询操作;

在MySQL中一切皆为表;


4.1 单行子查询

单行子查询表示子查询结果中只有一条记录, 通常我们可以将返回一条记录的子查询作为条件的一部分, 这个条件比较可以是=, >, <, between … 等;

如:

  • 显示SMITH同一部门的员工

对于该问题而言, 可以先通过子查询找出SMITH的部门号:

select deptno from emp where ename='SMITH';

结果为:

找到部门号后对整个emp表进行查询, 并通过deptno = (子查询结果)的方式:

select * from emp where deptno=(select deptno from emp where ename='SMITH');

结果为:


4.2 多行子查询

多行子查询时, 子查询结果通常存在多行, 多行的子查询结果可以作为一个新的临时表进行使用;

  • 查询和10号部门的工作岗位相同的雇员名字, 岗位, 工资, 部门号, 但是不包含10号部门自己

    1. 找出10号部门的员工所有的工作岗位:

      select job from emp where deptno=10;
      

      结果为:

    2. 通过IN子表来判断所有该工作岗位的对应所需信息的记录

      select ename, job, sal, deptno from emp where job in (select job from emp where deptno=10);
      

      结果为:

    3. 将所查询出的结果通过AND增加并列条件来排除部门号为10的员工

      select ename, job, sal, deptno from emp where job in (select job from emp where deptno=10) and deptno <> 10;
      
    4. 最终结果

  • 显示工资比部门30所有员工的工资高的员工的姓名, 工资, 和部门号

    这里有两种解法, 分别为使用聚合函数MAX()找出部门号为30的员工的最高工资, 还有一种方式是找出部门号30的所有员工的工资成为子表, 并通过> ALL (子表)关键字来找出比子表所有员工sal要大的记录;

    对应的聚合函数方式的子查询为:

    select ename, sal, deptno from emp where sal > (select max(sal) from emp where deptno = 30);
    +-------+---------+--------+
    | ename | sal     | deptno |
    +-------+---------+--------+
    | JONES | 2975.00 |     20 |
    | SCOTT | 3000.00 |     20 |
    | KING  | 5000.00 |     10 |
    | FORD  | 3000.00 |     20 |
    +-------+---------+--------+
    4 rows in set (0.00 sec)
    

    由于此处为多行子查询, 因此对上述的查询语句不进行解释;

    多列子查询可以使用ANY, ALL等关键字来进行配合比较;

    1. 先找出部门号30的所有员工的sal

      select sal from emp where deptno=30;
      

      结果为:

    2. 查询出子表后通过条件与关键字ALL来比较sal大于该子查询结果表中所有sal的记录

      select ename, sal, deptno from emp where sal > all (select sal from emp where deptno=30);
      
    3. 最终结果

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

    此处的条件较于宽泛, 与上一题类似, 不过在该题中可以使用ANY关键字进行比较;

    对应的SQL语句为:

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

    ALL不同, ANY表示任意的意思, 而ALL表示全部;

    该题与上一题中对应的意思是:

    • ALL

      子查询结果中所有的记录;

    • ANY

      子查询结果中的任意一条记录;

    对应的结果为:


4.3 多列子查询

单行子查询通常表示子查询结果只返回单行单列的记录, 而多行子查询则表示子查询结果为单列多行的记录, 而多列子查询表示结果返回多个列记录的查询语句;

  • 查询和SMITH的部门和岗位完全相同的所有雇员, 不含SMITH本人;

    1. 先通过子查询查出SMITH的部门和岗位

      select deptno, job from emp where ename ='SMITH';
      

      结果为:

    2. 通过多列单行的比较来比较是否符合的记录

      MySQL中支持对多列单行数据进行逻辑比较, 如= (column1, column2)等;

      通过该方式来查询emp表与返回的单行多列数据进行比较的对应的sql语句为:

      select * from emp where (deptno, job) = (select deptno, job from emp where ename ='SMITH');
      

      结果为:

    3. 通过AND增加并列条件来排除SMITH本人

      select * from emp where (deptno, job) = (select deptno, job from emp where ename ='SMITH') and ename <> 'SMITH';
      
    4. 最终查询结果


4.4 在 from 子句中使用的子查询

在上文中提到了, 我们可以对SELECT查询出的表作为子查询临时表, 而子查询表同样是一张表, 可以视该表为一张临时表进行查询;


4.4.1 显示每个高于自己部门平均工资的姓名, 部门, 工资, 平均工资
  1. 在该题中首先要准备一张子表, 该子表需要有平均工资与部门号因此来查出各个部门的平均工资

    同时出现了各个部门说明需要根据部门进行GROUP BY分组;

    对应的sql语句为:

    select deptno, avg(sal) from emp group by deptno;
    

    结果为:

  2. 这张表需要与另一张表进行连接, 但由于该表与另一张表emp的列值不同因此无法使用JOIN, 只能使用笛卡尔积的方式, 同时在笛卡尔积后需要筛选掉无用的数据

    select ename, emp.deptno, sal, asal from emp, (select deptno, avg(sal) asal from emp group by deptno) tmp where emp.deptno=tmp.deptno;
    

    对应的结果为:

  3. 根据条件筛选记录

    此时出现了一张新的表, 表中有每位雇员的薪资与平均薪资;

    而该题需要薪资高于部门平均薪资的记录, 因此需要使用AND来增加并列条件;

    select ename, emp.deptno, sal, asal from emp, (select deptno, avg(sal) asal from emp group by deptno) tmp where emp.deptno=tmp.deptno and sal>asal;
    
  4. 最终结果


4.4.2 查找每个部门工资最高的人的姓名, 工资, 部门以及最高工资

该题与上一题4.4.1的解题思路基本相同, 即设计出一张子表找出各个部门的最高工资与部门号, 随后进行笛卡尔积最后进行筛选;

  • 子查询找出各个部门的最高工资与部门号

    通过部门号进行筛选, 同样需要使用GROUP BY;

    select deptno, max(sal) from emp group by deptno;
    

    结果为:

  • 进行笛卡尔积并筛选掉无效记录

    select * from emp, (select deptno, max(sal) from emp group by deptno) tmp where tmp.deptno=emp.deptno;
    
  • 筛选掉无效的记录后通过AND增加条件筛选出sal=max(sal)的记录

    select * from emp, (select deptno, max(sal) maxsal from emp group by deptno) tmp where tmp.deptno=emp.deptno and maxsal=sal;
    
  • 最终选择列进行展示

    select ename, sal, emp.deptno, maxsal from emp, (select deptno, max(sal) maxsal from emp group by deptno) tmp where tmp.deptno=emp.deptno and maxsal=sal;
    
  • 结果


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

该题的表可以使用emp表与dept两张表, 对应的解法也有两种:

  • 多表查询

    使用多表查询进行查询时同样需要对两张表进行笛卡尔积, 随后通过条件筛选筛选掉无用的记录:

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

    在此处我们需要显示部门名, 编号, 地址以及人员数量, 由于人员数量需要用聚合函数COUNT, 因此可以先将前三列进行筛选;

    select dname, dept.deptno, loc from emp, dept where emp.deptno=dept.deptno;
    

    对应的结果为:

    接下来需要分组与聚合统计, 其中分组为每个部门的分组, 聚合统计则是针对各个部门的人数进行统计, 因此拟出下步的sql语句为:

    select dname, dept.deptno, loc, count(ename) from emp, dept where emp.deptno=dept.deptno group deptno; # Error
    

    但是这一步的sql语句将会报错:

    select dname, dept.deptno, loc, count(ename) from emp, dept where emp.deptno=dept.deptno group by deptno;
    ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'scott.dept.dname' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
    

    本质原因是在使用SELECT 聚合函数时, SELECT后跟随的column需要满足两个条件之一:

    1. 同样为GROUP BY分组的其中一列
    2. 使用聚合函数的一列

    因此这里无法使用聚合函数, 只能在语句末尾对剩余两列进行GROUP BY:

    select dname, dept.deptno, loc, count(ename) from emp, dept where emp.deptno=dept.deptno group by deptno, dname, loc;
    

    最终的查询结果为:

  • 子查询

    使用子查询的方式与4.4.2, 4.4.1的方式类似, 即对emp表使用聚合函数与分组作为子查询查询出子表(部门编号与各部门人数);

    随后对查询出的子表与dept表进行笛卡尔积, 最后筛选出需要的数据;

    1. 子查询语句查询出临时表

      select deptno, count(ename) count from emp group by deptno;
      

      对应的结果为:

    2. 进行笛卡尔积并筛选掉无效记录

      select * from dept, (select deptno, count(ename) count from emp group by deptno) tmp where tmp.deptno = dept.deptno;
      
    3. 最终结果


4.5 合并查询

通常情况下, 实际的应用中, 为了合并多个SELECT的执行结果, 可以使用集合操作符union, union all来进行操作;


4.5.1 UNION 关键字

该关键字用来获取两个查询结果的并集, 当出现重复数据时将会去重;

假设题目为:

  • 查询工资大于2500或是职位是MANAGER的员工

在这一题中我们可以使用OR进行查询;

select ename, sal, job from emp where sal>2500 or job = 'MANAGER';
+-------+---------+-----------+
| ename | sal     | job       |
+-------+---------+-----------+
| JONES | 2975.00 | MANAGER   |
| BLAKE | 2850.00 | MANAGER   |
| CLARK | 2450.00 | MANAGER   |
| SCOTT | 3000.00 | ANALYST   |
| KING  | 5000.00 | PRESIDENT |
| FORD  | 3000.00 | ANALYST   |
+-------+---------+-----------+
6 rows in set (0.00 sec)

但除了OR以外, 我们可以将两个条件各作为一条查询语句, 并使用关键字UNION将两个语句查询出来的结果进行并集;

对应的SQL语句为:

select ename, sal, job from emp where sal>2500 
union
select ename, sal, job from emp where job='MANAGER';

结果与使用OR的结果相同, 此处不进行赘述;


4.5.2 UNION ALL 关键字

该关键字与UNION关键字类似, 与之不同的是该关键字并不会对重复记录进行去重;

此处的例题同样使用:

  • 查询工资大于2500或是职位是MANAGER的员工

使用UNION ALL作为关键字的SQL语句为如下:

select ename, sal, job from emp where sal>2500 
union all
select ename, sal, job from emp where job='MANAGER';

最终结果为:


5 表的内外连接

通常情况下, 多表之间可以进行连接, 常有的是内连接与外连接, 上文所提到的笛卡尔积的方式其次就是内连接的一种, 也是在开发过程中使用最多的连接查询;

其次在上文中所提到的所有的连接方式都属于内连接;


5.1 内连接

内连接的语法为如下:

SELECT column FROM table_1 INNER JOIN table_2 ON 连接条件 AND 其他条件 ...;

与笛卡尔积作为比较的就是上文中所使用的笛卡尔积写法中的","换成了INNER JOIN;

假设存在一个案例:

  • 显示SMITH的名字和部门名称

若是使用之前的写法, 对应的SQL语句为:

select ename, emp.deptno, dname from emp, dept where emp.deptno=dept.deptno and ename='SMITH';

对应的结果为:

而若是使用标准的内连接写法, 对应的SQL语句则为:

select ename, emp.deptno, dname from emp inner join dept where emp.deptno=dept.deptno and ename='SMITH';

对应的结果为:

结果与上一个结果相同;


5.2 外连接

除了内连接以外还有一种连接方式被称为外连接;

外连接通常采用LEFT/RIGHT JOIN的方式对两张表进行连接;

即分为:

  • 左连接 - LEFT JOIN
  • 右连接 - RIGHT JOIN

5.2.1 左外连接

假设两张表进行联合查询, 如果左侧的表完全显示, 我们就说是左外连接;

对应的语法为:

SELECT column1, column2... FROM table1 LEFT JOIN table2 ON condition;

假设存在两张表, 对应的表结构与所插入数据为如下:

  • 表结构

    show create table exam\G
    *************************** 1. row ***************************Table: exam
    Create Table: CREATE TABLE `exam` (`id` int DEFAULT NULL,`grade` int DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
    1 row in set (0.00 sec)mysql> show create table stu\G
    *************************** 1. row ***************************Table: stu
    Create Table: CREATE TABLE `stu` (`id` int DEFAULT NULL,`name` varchar(30) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
    1 row in set (0.00 sec)
    
  • 表内数据

对应的题目为:

  • 查询所有学生的成绩, 如果这个学生没有成绩, 也要将学生的个人信息显示出来

在这一题中, 可以看到条件, 如果学生没有成绩, 也要将学生的个人信息进行显示, 这也说明这里采用的是左外连接;

对应的SQL语句为:

select * from stu left join exam on exam.id=stu.id;

针对左外连接而言, 实际上主表将在左侧, 而副表将在右侧;


5.2.2 右外连接

假设两张表进行联合查询, 同样的如果右侧的表完全显示, 我们就说是右外连接;

语法为:

SELECT column1, column2... FROM table1 RIGHT JOIN table2 ON condition;
  • stu表和exam表联合查询, 将所有的成绩都显示出来, 即使这个成绩没有学生与它对应, 也进行显示;

5.2.1的例题相同, 对应的SQL语句为:

select * from stu right join exam on exam.id=stu.id;

对应的结果为:


5.2.3 练习

回到Oracle 9i经典测试用表进行练习;

  • 列出部门名称和这些部门的员工信息, 同时列出没有员工的部门

部门名称和这些部门的员工信息, 说明查询中存在多表;

而列出没有员工的部门说明部门表dept是主表, 而对应的员工表emp为副表;

分别都可以进行左右外连接, 只需要控制主表与副表的位置;

  • 左外连接方式

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

    查询结果为:

  • 右外连接方式

    与左外连接相同, 只不过需要调转主表与副表的位置;

     select dname, emp.* from emp right join dept on dept.deptno=emp.deptno;
    

    查询结果为:


6 总结

在MySQL中, 无论是物理磁盘中存在的表还是查询中出现的中间产物表, 都视为表, 可以这么说:

  • "在MySQL中, 一切皆为表”

同时在进行多表查询时, 本质上就是通过各种连接方式, 将多表问题转化为单表问题;

http://www.dtcms.com/a/561725.html

相关文章:

  • openpi π 0.5复现 实战
  • git命令和markdown语法参考
  • 域名如何跟网站绑定网站托管怎做
  • 怎样可以快速增加网站的反链寮步网站建设哪家好
  • 四.docker容器数据卷
  • Sora 2 引爆后,AI 视频赛道正进入「超级加速」
  • 二叉树最小深度解题思路
  • 网站建设与开发 期末作品公司网站更换域名流程
  • 佛山网站建设在哪班级优化大师手机版下载
  • 如何在VScode环境下使用git进行版本控制,并上传到gitee远程仓库
  • 个人网站开发项目报告数据库营销
  • 自适应网站有哪些标签在线设计平台
  • 达梦数据库配置SSL通信加密
  • 【STL】set、multiset、unordered_set、unordered_multiset 的区别
  • HTTP 协议和 MQTT 协议的区别
  • 景区门户网站建设ui设计可以在ipad上面做嘛?
  • 2025年江西省职业院校技能大赛高职组“区块链技术应用”竞赛第六套任务书解析答案
  • 巴中房产网站建设推广网站发布文章
  • 北京网站建设价钱莱芜金点子信息港招聘
  • 摄影入门学习笔记
  • 网站设置怎么调济南网站建设方案书范文
  • 服务器怎么放网站吗国家商标免费查询入口
  • iOS八股文之 组件化
  • 系统规划与管理师 论文范文
  • visual studio做的网站商品推广软文800字
  • 个人网站推广方法小型的游戏网站怎么做
  • Photoshop - Photoshop 工具栏(22)单行选框工具
  • 郑州网站设计见效快服装设计网站有哪些
  • 第一章:从零开始构建你的第一个C#/.NET应用程序
  • 【51单片机】【protues仿真】基于51单片机波形发生器系统