• MySQL-多表查询


    概述

    数据准备

    SQL脚本

    1. #建议:创建新的数据库
    2. create database db04;
    3. use db04;
    4. -- 部门表
    5. create table tb_dept
    6. (
    7. id int unsigned primary key auto_increment comment '主键ID',
    8. name varchar(10) not null unique comment '部门名称',
    9. create_time datetime not null comment '创建时间',
    10. update_time datetime not null comment '修改时间'
    11. ) comment '部门表';
    12. -- 部门表测试
    13. insert into tb_dept (id, name, create_time, update_time)
    14. values (1, '学工部', now(), now()),
    15. (2, '教研部', now(), now()),
    16. (3, '咨询部', now(), now()),
    17. (4, '就业部', now(), now()),
    18. (5, '人事部', now(), now());
    19. -- 员工表
    20. create table tb_emp
    21. (
    22. id int unsigned primary key auto_increment comment 'ID',
    23. username varchar(20) not null unique comment '用户名',
    24. password varchar(32) default '123456' comment '密码',
    25. name varchar(10) not null comment '姓名',
    26. gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
    27. image varchar(300) comment '图像',
    28. job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师',
    29. entrydate date comment '入职时间',
    30. dept_id int unsigned comment '部门ID',
    31. create_time datetime not null comment '创建时间',
    32. update_time datetime not null comment '修改时间'
    33. ) comment '员工表';
    34. -- 员工表测试数据
    35. INSERT INTO tb_emp(id, username, password, name, gender, image, job, entrydate,dept_id, create_time, update_time)
    36. VALUES
    37. (1,'jinyong','123456','金庸',1,'1.jpg',4,'2000-01-01',2,now(),now()),
    38. (2,'zhangwuji','123456','张无忌',1,'2.jpg',2,'2015-01-01',2,now(),now()),
    39. (3,'yangxiao','123456','杨逍',1,'3.jpg',2,'2008-05-01',2,now(),now()),
    40. (4,'weiyixiao','123456','韦一笑',1,'4.jpg',2,'2007-01-01',2,now(),now()),
    41. (5,'changyuchun','123456','常遇春',1,'5.jpg',2,'2012-12-05',2,now(),now()),
    42. (6,'xiaozhao','123456','小昭',2,'6.jpg',3,'2013-09-05',1,now(),now()),
    43. (7,'jixiaofu','123456','纪晓芙',2,'7.jpg',1,'2005-08-01',1,now(),now()),
    44. (8,'zhouzhiruo','123456','周芷若',2,'8.jpg',1,'2014-11-09',1,now(),now()),
    45. (9,'dingminjun','123456','丁敏君',2,'9.jpg',1,'2011-03-11',1,now(),now()),
    46. (10,'zhaomin','123456','赵敏',2,'10.jpg',1,'2013-09-05',1,now(),now()),
    47. (11,'luzhangke','123456','鹿杖客',1,'11.jpg',5,'2007-02-01',3,now(),now()),
    48. (12,'hebiweng','123456','鹤笔翁',1,'12.jpg',5,'2008-08-18',3,now(),now()),
    49. (13,'fangdongbai','123456','方东白',1,'13.jpg',5,'2012-11-01',3,now(),now()),
    50. (14,'zhangsanfeng','123456','张三丰',1,'14.jpg',2,'2002-08-01',2,now(),now()),
    51. (15,'yulianzhou','123456','俞莲舟',1,'15.jpg',2,'2011-05-01',2,now(),now()),
    52. (16,'songyuanqiao','123456','宋远桥',1,'16.jpg',2,'2007-01-01',2,now(),now()),
    53. (17,'chenyouliang','123456','陈友谅',1,'17.jpg',NULL,'2015-03-21',NULL,now(),now());

    介绍

    多表查询:查询时从多张表中获取所需数据

    单表查询的SQL语句:select 字段列表 from 表名;

    那么要执行多表查询,只需要使用逗号分隔多张表即可,如: select 字段列表 from 表1, 表2;

    查询用户表和部门表中的数据:

    select * from  tb_emp , tb_dept;

    此时,我们看到查询结果中包含了大量的结果集,总共85条记录,而这其实就是员工表所有的记录(17行)与部门表所有记录(5行)的所有组合情况,这种现象称之为笛卡尔积。

    笛卡尔积:笛卡尔乘积是指在数学中,两个集合(A集合和B集合)的所有组合情况。

     在多表查询时,需要消除无效的笛卡尔积,只保留表关联部分的数据

    在SQL语句中,如何去除无效的笛卡尔积呢?只需要给多表查询加上连接查询的条件即可。

    select * from tb_emp , tb_dept where tb_emp.dept_id = tb_dept.id ;

    由于id为17的员工,没有dept_id字段值,所以在多表查询时,根据连接查询的条件并没有查询到。

    分类

    多表查询可以分为:

    1. 连接查询

      • 内连接:相当于查询A、B交集部分数据

     

    1. 外连接

      • 左外连接:查询左表所有数据(包括两张表交集部分数据)

      • 右外连接:查询右表所有数据(包括两张表交集部分数据)

    2. 子查询

    内连接

    内连接查询:查询两表或多表中交集部分数据。

    内连接从语法上可以分为:

    • 隐式内连接

    • 显式内连接

    隐式内连接语法:

    select  字段列表   from1 , 表2   where  条件 ... ;

    显式内连接语法:

    select  字段列表   from1  [ inner ]  join2  on  连接条件 ... ;

    案例:查询员工的姓名及所属的部门名称

    隐式内连接实现

    1. select tb_emp.name , tb_dept.name -- 分别查询两张表中的数据
    2. from tb_emp , tb_dept -- 关联两张表
    3. where tb_emp.dept_id = tb_dept.id; -- 消除笛卡尔积

    显式内连接实现

    1. select tb_emp.name , tb_dept.name
    2. from tb_emp inner join tb_dept
    3. on tb_emp.dept_id = tb_dept.id;

    多表查询时给表起别名:

    • tableA as 别名1 , tableB as 别名2 ;

    • tableA 别名1 , tableB 别名2 ;

    使用了别名的多表查询:

    1. select emp.name , dept.name
    2. from tb_emp emp inner join tb_dept dept
    3. on emp.dept_id = dept.id;

    注意事项:

    一旦为表起了别名,就不能再使用表名来指定对应的字段了,此时只能够使用别名来指定字段。

    外连接

    外连接分为两种:左外连接 和 右外连接。

    左外连接语法结构:

    select  字段列表   from1  left  [ outer ]  join2  on  连接条件 ... ;

     右外连接相当于查询表2(右表)的所有数据,当然也包含表1和表2交集部分的数据。

    案例:查询员工表中所有员工的姓名, 和对应的部门名称

    1. -- 左外连接:以left join关键字左边的表为主表,查询主表中所有数据,以及和主表匹配的右边表中的数据
    2. select emp.name , dept.name
    3. from tb_emp AS emp left join tb_dept AS dept
    4. on emp.dept_id = dept.id;

    案例:查询部门表中所有部门的名称, 和对应的员工名称  

    1. -- 右外连接
    2. select dept.name , emp.name
    3. from tb_emp AS emp right join tb_dept AS dept
    4. on emp.dept_id = dept.id;

    注意事项:

    左外连接和右外连接是可以相互替换的,只需要调整连接查询时SQL语句中表的先后顺序就可以了。而我们在日常开发使用时,更偏向于左外连接。

    子查询

    介绍

    SQL语句中嵌套select语句,称为嵌套查询,又称子查询。

    SELECT  *  FROM   t1   WHERE  column1 =  ( SELECT  column1  FROM  t2 ... );

    子查询外部的语句可以是insert / update / delete / select 的任何一个,最常见的是 select。

    根据子查询结果的不同分为:

    1. 标量子查询(子查询结果为单个值[一行一列])

    2. 列子查询(子查询结果为一列,但可以是多行)

    3. 行子查询(子查询结果为一行,但可以是多列)

    4. 表子查询(子查询结果为多行多列[相当于子查询结果是一张表])

    子查询可以书写的位置:

    1. where之后

    2. from之后

    3. select之后

    标量子查询

    子查询返回的结果是单个值(数字、字符串、日期等),最简单的形式,这种子查询称为标量子查询。

    常用的操作符: = <> > >= < <=

    案例1:查询"教研部"的所有员工信息

    可以将需求分解为两步:

    1. 查询 "教研部" 部门ID

    2. 根据 "教研部" 部门ID,查询员工信息

    1. -- 1.查询"教研部"部门ID
    2. select id from tb_dept where name = '教研部'; #查询结果:2
    3. -- 2.根据"教研部"部门ID, 查询员工信息
    4. select * from tb_emp where dept_id = 2;
    5. -- 合并出上两条SQL语句
    6. select * from tb_emp where dept_id = (select id from tb_dept where name = '教研部');

    案例2:查询在 "方东白" 入职之后的员工信息

    可以将需求分解为两步:

    1. 查询 方东白 的入职日期

    2. 查询 指定入职日期之后入职的员工信息

    1. -- 1.查询"方东白"的入职日期
    2. select entrydate from tb_emp where name = '方东白'; #查询结果:2012-11-01
    3. -- 2.查询指定入职日期之后入职的员工信息
    4. select * from tb_emp where entrydate > '2012-11-01';
    5. -- 合并以上两条SQL语句
    6. select * from tb_emp where entrydate > (select entrydate from tb_emp where name = '方东白');

    列子查询

    子查询返回的结果是一列(可以是多行),这种子查询称为列子查询。

    常用的操作符:

     案例:查询"教研部"和"咨询部"的所有员工信息

    分解为以下两步:

    1. 查询 "销售部" 和 "市场部" 的部门ID

    2. 根据部门ID, 查询员工信息

    1. -- 1.查询"销售部"和"市场部"的部门ID
    2. select id from tb_dept where name = '教研部' or name = '咨询部'; #查询结果:3,2
    3. -- 2.根据部门ID, 查询员工信息
    4. select * from tb_emp where dept_id in (3,2);
    5. -- 合并以上两条SQL语句
    6. select * from tb_emp where dept_id in (select id from tb_dept where name = '教研部' or name = '咨询部');

    行子查询

    子查询返回的结果是一行(可以是多列),这种子查询称为行子查询。

    常用的操作符:= 、<> 、IN 、NOT IN

    案例:查询与"韦一笑"的入职日期及职位都相同的员工信息

    可以拆解为两步进行:

    1. 查询 "韦一笑" 的入职日期 及 职位

    2. 查询与"韦一笑"的入职日期及职位相同的员工信息

    1. -- 查询"韦一笑"的入职日期 及 职位
    2. select entrydate , job from tb_emp where name = '韦一笑'; #查询结果: 2007-01-01 , 2
    3. -- 查询与"韦一笑"的入职日期及职位相同的员工信息
    4. select * from tb_emp where (entrydate,job) = ('2007-01-01',2);
    5. -- 合并以上两条SQL语句
    6. select * from tb_emp where (entrydate,job) = (select entrydate , job from tb_emp where name = '韦一笑');

    表子查询

    子查询返回的结果是多行多列,常作为临时表,这种子查询称为表子查询。

    案例:查询入职日期是 "2006-01-01" 之后的员工信息 , 及其部门信息

    分解为两步执行:

    1. 查询入职日期是 "2006-01-01" 之后的员工信息

    2. 基于查询到的员工信息,在查询对应的部门信息

    1. select * from emp where entrydate > '2006-01-01';
    2. select e.*, d.* from (select * from emp where entrydate > '2006-01-01') e left join dept d on e.dept_id = d.id ;

     

  • 相关阅读:
    动手写数据库:实现记录管理
    VUE3项目element-plus的icons全局引入和按需引入的打包比较
    几款好用到爆炸的在线画图工具
    PyQt5 PyQtChart
    面试突击46:公平锁和非公平锁有什么区别?
    R 语言详细安装教程(保姆级)及 RStudio简易安装教程
    直播视频处理过程
    训练人工智能机器人的软实力
    docker容器启动rabbitmq
    mysql 中 varchar 和 text 的区别
  • 原文地址:https://blog.csdn.net/LU58542226/article/details/132990379