mysql 数据库 IV(多表查询)

1.今日内容

  1. 多表联合查询

    • 内连接 inner join ...on ... :只连接匹配的行
    • 外连接:只连接匹配的行
      • 左外连接 left join ... on ...
      • 右外连接 right join ... on ...
      • 全外连接 full join
    select 字段列表 from 表1 inner|left|right join 
    									   表2 on 表1.字段 = 表2.字段
    
  2. 子查询

    ​ 子查询是将一个查询语句嵌套在另一个查询语句中;内层查询语句的查询结果,可以为外层查询语句提供查询条件;可以包含:in 、not in、any、all、exists、和not exists等关键字。

    • 带in关键字的字查询
    • 带比较符关键字的子查询(=、!=、<、>等)
    • 带exists关键字的子查询

2.具体内容

  1. 数据准备

    数据准备示例
    mysql> use day41;
    Database changed
    
    
    # 建表
    mysql> create table department(
        -> id int,
        -> name varchar(20) 
        -> );
    Query OK, 0 rows affected (0.05 sec)
    
    mysql> create table employee(
        -> id int primary key auto_increment,
        -> name varchar(20),
        -> sex enum('male','female') not null default 'male',
        -> age int,
        -> dep_id int
        -> );
    Query OK, 0 rows affected (0.02 sec)
    
    # 插入数据
    mysql> insert into department values
        -> (200,'技术'),
        -> (201,'人力资源'),
        -> (202,'销售'),
        -> (203,'运营');
    Query OK, 4 rows affected (0.01 sec)
    Records: 4  Duplicates: 0  Warnings: 0
    
    mysql> insert into employee(name,sex,age,dep_id) values
        -> ('egon','male',18,200),
        -> ('alex','female',48,201),
        -> ('wupeiqi','male',38,201),
        -> ('yuanhao','female',28,202),
        -> ('liwenzhou','male',18,200),
        -> ('jingliyang','female',18,204)
        -> ;
    Query OK, 6 rows affected (0.00 sec)
    Records: 6  Duplicates: 0  Warnings: 0
    
    # 查看表结构和数据
    mysql> desc department;
    +-------+-------------+------+-----+---------+-------+
    | Field | Type        | Null | Key | Default | Extra |
    +-------+-------------+------+-----+---------+-------+
    | id    | int(11)     | YES  |     | NULL    |       |
    | name  | varchar(20) | YES  |     | NULL    |       |
    +-------+-------------+------+-----+---------+-------+
    2 rows in set (0.01 sec)
    
    mysql> desc employee;
    +--------+-----------------------+------+-----+---------+----------------+
    | Field  | Type                  | Null | Key | Default | Extra          |
    +--------+-----------------------+------+-----+---------+----------------+
    | id     | int(11)               | NO   | PRI | NULL    | auto_increment |
    | name   | varchar(20)           | YES  |     | NULL    |                |
    | sex    | enum('male','female') | NO   |     | male    |                |
    | age    | int(11)               | YES  |     | NULL    |                |
    | dep_id | int(11)               | YES  |     | NULL    |                |
    +--------+-----------------------+------+-----+---------+----------------+
    5 rows in set (0.00 sec)
    
    mysql> select * from department;
    +------+--------------+
    | id   | name         |
    +------+--------------+
    |  200 | 技术         |
    |  201 | 人力资源     |
    |  202 | 销售         |
    |  203 | 运营         |
    +------+--------------+
    4 rows in set (0.00 sec)
    
    mysql> select * from employee;
    +----+------------+--------+------+--------+
    | id | name       | sex    | age  | dep_id |
    +----+------------+--------+------+--------+
    |  1 | egon       | male   |   18 |    200 |
    |  2 | alex       | female |   48 |    201 |
    |  3 | wupeiqi    | male   |   38 |    201 |
    |  4 | yuanhao    | female |   28 |    202 |
    |  5 | liwenzhou  | male   |   18 |    200 |
    |  6 | jingliyang | female |   18 |    204 |
    +----+------------+--------+------+--------+
    6 rows in set (0.00 sec)
    
  1. 交叉连接

    (不适合任何匹配条件,生成笛卡尔积)

    mysql> select * from employee,department;
    +----+------------+--------+------+--------+------+--------------+
    | id | name       | sex    | age  | dep_id | id   | name         |
    +----+------------+--------+------+--------+------+--------------+
    |  1 | egon       | male   |   18 |    200 |  200 | 技术         |
    |  1 | egon       | male   |   18 |    200 |  201 | 人力资源     |
    |  1 | egon       | male   |   18 |    200 |  202 | 销售         |
    |  1 | egon       | male   |   18 |    200 |  203 | 运营         |
    |  2 | alex       | female |   48 |    201 |  200 | 技术         |
    |  .....																												|
    +----+------------+--------+------+--------+------+--------------+
    24 rows in set (0.01 sec)
    
  2. 内连接

    • 只连接匹配的行
    • 找两张表共有的部分,相当于利用条件从笛卡尔积结果中筛选出正确的结果
    • 取出两张表中存在连接匹配关系的记录
    select * from 表1 inner join 表2  on 条件
    # select * from department as t1 inner join employee as t2 on t1.id = t2.dep_id;
    
    # 示例
    mysql> select * from employee inner join department on employee.dep_id = department.id;
    +----+-----------+--------+------+--------+------+--------------+
    | id | name      | sex    | age  | dep_id | id   | name         |
    +----+-----------+--------+------+--------+------+--------------+
    |  1 | egon      | male   |   18 |    200 |  200 | 技术         |
    |  2 | alex      | female |   48 |    201 |  201 | 人力资源     |
    |  3 | wupeiqi   | male   |   38 |    201 |  201 | 人力资源     |
    |  4 | yuanhao   | female |   28 |    202 |  202 | 销售         |
    |  5 | liwenzhou | male   |   18 |    200 |  200 | 技术         |
    +----+-----------+--------+------+--------+------+--------------+
    5 rows in set (0.01 sec)
    
  3. 左外连接

    • 优先显示左表全部记录
    • 在内连接的基础上增加左表有,右表没有的结果
    select * from 表1 left join 表2 on 条件
    #select * from department as t1 left join employee as t2 on t1.id = t2.dep_id;
    
    # 示例
    mysql> select employee.id,employee.name,department.name as depart_name from employee left join department on employee.dep_id = department.id;
    +----+------------+--------------+
    | id | name       | depart_name  |
    +----+------------+--------------+
    |  1 | egon       | 技术         |
    |  5 | liwenzhou  | 技术         |
    |  2 | alex       | 人力资源     |
    |  3 | wupeiqi    | 人力资源     |
    |  4 | yuanhao    | 销售         |
    |  6 | jingliyang | NULL         |
    +----+------------+--------------+
    6 rows in set (0.00 sec)
    
  4. 右外连接

    • 优先显示右表全部记录
    • 在内连接的基础上增加右边有,左边没有的结果
    select * from 表1 right join 表2 on 条件
    
    # 示例
    mysql> select * from department t1 right join employee as t2 on t1.id = t2.dep_id;
    +------+--------------+----+------------+--------+------+--------+
    | id   | name         | id | name       | sex    | age  | dep_id |
    +------+--------------+----+------------+--------+------+--------+
    |  200 | 技术         |  1 | egon       | male   |   18 |    200 |
    |  200 | 技术         |  5 | liwenzhou  | male   |   18 |    200 |
    |  201 | 人力资源     |  2 | alex       | female |   48 |    201 |
    |  201 | 人力资源     |  3 | wupeiqi    | male   |   38 |    201 |
    |  202 | 销售         |  4 | yuanhao    | female |   28 |    202 |
    | NULL | NULL         |  6 | jingliyang | female |   18 |    204 |
    +------+--------------+----+------------+--------+------+--------+
    6 rows in set (0.00 sec)
    
    
  5. 全外连接

    • 显示左右两个表的全部记录
    • 在内连接的基础上增加左边有右边没有,和右边有左边没有的结果
    • 不支持 full join ,但可以间接实现全外连接
    mysql> select * from employee left join department on employee.dep_id = department.id
        -> union
        -> select * from department t1 right join employee as t2 on t1.id = t2.dep_id;                                                                              +------+--------------+--------+------------+--------+------+--------------+
    | id   | name         | sex    | age        | dep_id | id   | name         |
    +------+--------------+--------+------------+--------+------+--------------+
    |    1 | egon         | male   | 18         | 200    |  200 | 技术         |
    |    5 | liwenzhou    | male   | 18         | 200    |  200 | 技术         |
    |    2 | alex         | female | 48         | 201    |  201 | 人力资源     |
    |    3 | wupeiqi      | male   | 38         | 201    |  201 | 人力资源     |
    |    4 | yuanhao      | female | 28         | 202    |  202 | 销售         |
    |    6 | jingliyang   | female | 18         | 204    | NULL | NULL         |
    |  200 | 技术         | 1      | egon       | male   |   18 | 200          |
    |  200 | 技术         | 5      | liwenzhou  | male   |   18 | 200          |
    |  201 | 人力资源     | 2      | alex       | female |   48 | 201          |
    |  201 | 人力资源     | 3      | wupeiqi    | male   |   38 | 201          |
    |  202 | 销售         | 4      | yuanhao    | female |   28 | 202          |
    | NULL | NULL         | 6      | jingliyang | female |   18 | 204          |
    +------+--------------+--------+------------+--------+------+--------------+
    12 rows in set (0.01 sec)
    
    • 练习
    练习
    # 找到技术部的所有人的名字
    mysql> select * from employee e inner join department d on e.dep_id = d.id where d.name = '技术';
    +-----------+
    | name      |
    +-----------+
    | egon      |
    | liwenzhou |
    +-----------+
    2 rows in set (0.00 sec)
    
    # 找到人力资源的年龄大于40岁的人的姓名
    mysql> select * from employee e inner join department d on e.dep_id = d.id where d.name = '人力资源' and age > 40;
    +------+
    | name |
    +------+
    | alex |
    +------+
    1 row in set (0.00 sec)
    
    # 找到年龄大于25岁的员工以及员工所在部门
    mysql> select e.name,d.name from employee e inner join department d on e.dep_id = d.id where age > 25;
    +---------+--------------+
    | name    | name         |
    +---------+--------------+
    | alex    | 人力资源     |
    | wupeiqi | 人力资源     |
    | yuanhao | 销售         |
    +---------+--------------+
    3 rows in set (0.00 sec)
    
    # 以内连接的方式查询employee和department表,并且以age字段的升序方式显示
    mysql> select * from employee e inner join department d on e.dep_id = d.id order by age;
    +----+-----------+--------+------+--------+------+--------------+
    | id | name      | sex    | age  | dep_id | id   | name         |
    +----+-----------+--------+------+--------+------+--------------+
    |  1 | egon      | male   |   18 |    200 |  200 | 技术         |
    |  5 | liwenzhou | male   |   18 |    200 |  200 | 技术         |
    |  4 | yuanhao   | female |   28 |    202 |  202 | 销售         |
    |  3 | wupeiqi   | male   |   38 |    201 |  201 | 人力资源     |
    |  2 | alex      | female |   48 |    201 |  201 | 人力资源     |
    +----+-----------+--------+------+--------+------+--------------+
    5 rows in set (0.01 sec)
    
    # 求每一个部门有多少人,按照人数从高到低排序
     select d.name,count(e.id) from employee e inner join department d on e.dep_id = d.id group by d.name order by count(e.id) desc;
    +--------------+-------------+
    | name         | count(e.id) |
    +--------------+-------------+
    | 技术         |           2 |
    | 人力资源     |           2 |
    | 销售         |           1 |
    +--------------+-------------+
    3 rows in set (0.01 sec)
    
  1. 带in 的字查询

    # 查询平均年龄在25岁以上的部门名
    mysql> select id,name from department 
    					where id in(
              		select dep_id from employee group by dep_id having avg(age) >25);
    +------+--------------+
    | id   | name         |
    +------+--------------+
    |  201 | 人力资源     |
    |  202 | 销售         |
    +------+--------------+
    2 rows in set (0.01 sec)
    
    # 查看技术部员工姓名
    mysql> select name from employee where dep_id in ( select id from department where name = '技术');
    +-----------+
    | name      |
    +-----------+
    | egon      |
    | liwenzhou |
    +-----------+
    2 rows in set (0.00 sec)
    
    # 查看不足1人的部门名(子查询得到的所有人的部门id)
    mysql> select name from department where id not in (select distinct dep_id from employee);
    +--------+
    | name   |
    +--------+
    | 运营   |
    +--------+
    1 row in set (0.00 sec)
    
  2. 带比较符的子查询

  3. 带exists的子查询

原文地址:https://www.cnblogs.com/xiaohei-chen/p/12193550.html