zoukankan      html  css  js  c++  java
  • MySQL之多表查询(笛卡尔积查询、内连接、外连接(左外连接,右外连接)、union、union all )

    多表查询
    测试数据
    create table emp (id int,name char(10),sex char,dept_id int);
    insert emp values(1,"大黄","m",1);
    insert emp values(2,"老王","m",2);
    insert emp values(3,"老李","w",30);
    
    #一张表示部门表
    #存在一些没有员工的的部门
    
    create table dept (id int,name char(10));
    insert dept values(1,"市场");
    insert dept values(2,"财务");
    insert dept values(3,"行政");
    
    1. 笛卡尔积查询
    # 笛卡尔积查询,
    mysql> select *from dept,emp;
    +------+--------+------+--------+------+---------+
    | id   | name   | id   | name   | sex  | dept_id |
    +------+--------+------+--------+------+---------+
    |    1 | 市场   |    1 | 大黄   | m    |       1 |
    |    2 | 财务   |    1 | 大黄   | m    |       1 |
    |    3 | 行政   |    1 | 大黄   | m    |       1 |
    |    1 | 市场   |    2 | 老王   | m    |       2 |
    |    2 | 财务   |    2 | 老王   | m    |       2 |
    |    3 | 行政   |    2 | 老王   | m    |       2 |
    |    1 | 市场   |    3 | 老李   | w    |      30 |
    |    2 | 财务   |    3 | 老李   | w    |      30 |
    |    3 | 行政   |    3 | 老李   | w    |      30 |
    +------+--------+------+--------+------+---------+
    9 rows in set (0.00 sec)
    
    
    
    # 改进版
    mysql> select *from dept,emp where dept.id = dept_id;
    +------+--------+------+--------+------+---------+
    | id   | name   | id   | name   | sex  | dept_id |
    +------+--------+------+--------+------+---------+
    |    1 | 市场   |    1 | 大黄   | m    |       1 |
    |    2 | 财务   |    2 | 老王   | m    |       2 |
    +------+--------+------+--------+------+---------+
    

    总结:

    1. 笛卡尔积查询的结果,存在很多错误的数据。即数据关联关系错误

      解决办法:

      select *from dept,emp where dept.id = dept_id;
      
    2. 同时笛卡尔积的结果,会产生重复的字段信息

      解决办法:

      select 指定字段... from dept,emp where dept.id = dept_id;
      
    2. 内连接

    内连接查询本质上就是笛卡尔积查询

    mysql> select *from dept join emp ;
    +------+--------+------+--------+------+---------+
    | id   | name   | id   | name   | sex  | dept_id |
    +------+--------+------+--------+------+---------+
    |    1 | 市场   |    1 | 大黄   | m    |       1 |
    |    2 | 财务   |    1 | 大黄   | m    |       1 |
    |    3 | 行政   |    1 | 大黄   | m    |       1 |
    |    1 | 市场   |    2 | 老王   | m    |       2 |
    |    2 | 财务   |    2 | 老王   | m    |       2 |
    |    3 | 行政   |    2 | 老王   | m    |       2 |
    |    1 | 市场   |    3 | 老李   | w    |      30 |
    |    2 | 财务   |    3 | 老李   | w    |      30 |
    |    3 | 行政   |    3 | 老李   | w    |      30 |
    +------+--------+------+--------+------+---------+
    9 rows in set (0.00 sec)
    
    mysql> select *from dept join emp on dept.id=emp.dept_id;
    +------+--------+------+--------+------+---------+
    | id   | name   | id   | name   | sex  | dept_id |
    +------+--------+------+--------+------+---------+
    |    1 | 市场   |    1 | 大黄   | m    |       1 |
    |    2 | 财务   |    2 | 老王   | m    |       2 |
    +------+--------+------+--------+------+---------+
    2 rows in set (0.00 sec)
    
    3. 外连接:左连接

    左边的表无论是否能够匹配 都要完整显示,右边即使没有也要显示出来

    # 需求:要查询所有员工以及所属的部门信息
    mysql> select * from emp left join dept on dept_id= dept.id;
    +------+--------+------+---------+------+--------+
    | id   | name   | sex  | dept_id | id   | name   |
    +------+--------+------+---------+------+--------+
    |    1 | 大黄   | m    |       1 |    1 | 市场   |
    |    2 | 老王   | m    |       2 |    2 | 财务   |
    |    3 | 老李   | w    |      30 | NULL | NULL   |
    +------+--------+------+---------+------+--------+
    3 rows in set (0.00 sec)
    
    # 注意 在外连接查询中 不能使用where关键字,必须使用on 专门来做表的对应关系
    
    
    
    4. 外连接:右连接

    右边的表无论是否能够匹配 都要完整显示,左边即使没有也要显示出来

    select *from dept full join emp on dept.id = emp.dept_id; 
    
    5. 外连接:全连接(不支持)

    无论是否匹配成功,两边表的数据都要全显示

    ##mysql 不支持
    select *from dept full join emp on dept.id = emp.dept_id; 
    
    
    # 可以转化一种思路,使用左连接 + 右连接
    select *from dept left join emp on dept.id=emp.dept_id
    union
    select *from dept right join emp on dept.id=emp.dept_id;
    
    6. union:联合两个表

    过滤重复,即重复的数据不显示。同时必须保证 两个表的列数要相同

    select * from emp
    union
    select * from emp;
    
    
    mysql> select * from emp
        -> union
        -> select * from emp;
    +------+--------+------+---------+
    | id   | name   | sex  | dept_id |
    +------+--------+------+---------+
    |    1 | 大黄   | m    |       1 |
    |    2 | 老王   | m    |       2 |
    |    3 | 老李   | w    |      30 |
    +------+--------+------+---------+
    3 rows in set (0.00 sec)
    
    7. union all :

    不过滤重复,即重复的数据可以显示。同时必须保证 两个表的列数要相同

    select * from emp
    union all
    select * from emp;
    
    
    mysql> select * from emp
        -> union all
        -> select * from emp;
    +------+--------+------+---------+
    | id   | name   | sex  | dept_id |
    +------+--------+------+---------+
    |    1 | 大黄   | m    |       1 |
    |    2 | 老王   | m    |       2 |
    |    3 | 老李   | w    |      30 |
    |    1 | 大黄   | m    |       1 |
    |    2 | 老王   | m    |       2 |
    |    3 | 老李   | w    |      30 |
    +------+--------+------+---------+
    6 rows in set (0.00 sec)
    

    总结:

    内连接表示,只显示匹配成功的记录。一般情况下,我们通常使用内连接

    外连接表示,没有匹配成功的也要显示

    练习:

    测试数据
    create table stu(id int primary key auto_increment,name char(10));
    
    create table tea(id int primary key auto_increment,name char(10));
    
    create table tsr(id int primary key auto_increment,t_id int,s_id int,
    foreign key(s_id) references stu(id),
    foreign key(t_id) references tea(id));
    
    insert into stu values(null,"张三"),(null,"李四");
    insert into tea values(null,"egon"),(null,"wer");
    insert into tsr values(null,1,1),(null,1,2),(null,2,2);
    
    
    
    需求:查出egon教过的学生

    使用内连接:

    mysql> select  * from tea join tsr join  stu on tea.id=tsr.t_id  and tsr.s_id = stu.id  where tea.name="egon";
    +----+------+----+------+------+----+--------+
    | id | name | id | t_id | s_id | id | name   |
    +----+------+----+------+------+----+--------+
    |  1 | egon |  1 |    1 |    1 |  1 | 张三   |
    |  1 | egon |  2 |    1 |    2 |  2 | 李四   |
    +----+------+----+------+------+----+--------+
    2 rows in set (0.00 sec)
    
    
    mysql> select  stu.name from tea join tsr join  stu on tea.id=tsr.t_id  and tsr.s_id = stu.id  where tea.name="egon";
    +--------+
    | name   |
    +--------+
    | 张三   |
    | 李四   |
    +--------+
    2 rows in set (0.00 sec)
    

    使用子查询:

    # 先查出egon对应的id
    select id from tea where name="egon";
    
    # 在tsr表中 查询 egon 教过学生 的id
    select s_id from tsr where  t_id = (select id from tea where name="egon");
    
    # 在学生表中查询出对应的id
    select stu.name from stu where id in (select s_id from tsr where  t_id = (select id from tea where name="egon"));
    
    
    
    mysql> select * from tea where name="egon";
    +----+------+
    | id | name |
    +----+------+
    |  1 | egon |
    +----+------+
    1 row in set (0.00 sec)
    
    
    mysql> select s_id from tsr where  t_id = (select id from tea where name="egon");
    +------+
    | s_id |
    +------+
    |    1 |
    |    2 |
    +------+
    2 rows in set (0.00 sec)
    
    
    mysql> select stu.name from stu where id in (select s_id from tsr where  t_id = (select id from tea where name="egon"));
    +--------+
    | name   |
    +--------+
    | 张三   |
    | 李四   |
    +--------+
    2 rows in set (0.27 sec)
    

    通常情况下,内连接能够查询出来的数据,使用子查询也能查询出来

  • 相关阅读:
    Java中Properties类的操作
    Java中Properties类的使用
    properties类的基本使用方法
    java.util.ResourceBundle使用详解
    java.util.ResourceBundle 用法小介
    java.util.Date和java.sql.Date的区别和相互转化
    response.setHeader()的用法
    Fiddler (二) Script 用法
    HTTP协议 (七) Cookie
    HTTP协议 (六) 状态码详解
  • 原文地址:https://www.cnblogs.com/plf-Jack/p/11189922.html
Copyright © 2011-2022 走看看