zoukankan      html  css  js  c++  java
  • MySQL学习笔记四之连接查询

    一、测试表:

      1. 学生表
      CREATE TABLE `students` (
            `id` int NOT NULL AUTO_INCREMENT,
            `name` varchar(12) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
            `gender` tinyint(1) DEFAULT NULL,
            `age` tinyint DEFAULT NULL,
            PRIMARY KEY (`id`)
      ) ENGINE=InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
    
      2. 课程表
      CREATE TABLE `subject` (
            `id` int NOT NULL AUTO_INCREMENT,
            `name` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '科目名称',
            PRIMARY KEY (`id`)
            ) ENGINE=InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
    
      3. 学生成绩表
      CREATE TABLE `score` (
            `id` int NOT NULL AUTO_INCREMENT,
            `subject_id` int DEFAULT NULL,
            `score` smallint DEFAULT NULL,
            `student_id` int DEFAULT NULL,
            PRIMARY KEY (`id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
    
      4. 学生成绩等级表:
      create table grade(
            id int primary key auto_increment,
            min_score tinyint(3),
            max_score tinyint(3),
            name char(1)
      )engine=innodb default charset=utf8mb4 collate=utf8mb4_unicode_ci;
      说明:表结构只为满足实验要求,没有实际业务逻辑参考价值。
    

    二、笛卡尔乘积现象:

      mysql> select * from subject su,score sc;
      | id | name   | id | subject_id | score | student_id |
      +----+--------+----+------------+-------+------------+
      |  5 | 物理   |  1 |          1 |    80 |          1 |
      |  4 | 化学   |  1 |          1 |    80 |          1 |
      |  3 | 英语   |  1 |          1 |    80 |          1 |
      |  2 | 数学   |  1 |          1 |    80 |          1 |
      |  1 | 语文   |  1 |          1 |    80 |          1 |
      |  5 | 物理   |  2 |          2 |    79 |          1 |
      |  4 | 化学   |  2 |          2 |    79 |          1 |
      |  3 | 英语   |  2 |          2 |    79 |          1 |
      |  2 | 数学   |  2 |          2 |    79 |          1 |
      |  1 | 语文   |  2 |          2 |    79 |          1 |
      |  5 | 物理   |  3 |          3 |  NULL |          1 |
      |  4 | 化学   |  3 |          3 |  NULL |          1 |
      |  3 | 英语   |  3 |          3 |  NULL |          1 |
      |  2 | 数学   |  3 |          3 |  NULL |          1 |
      |  1 | 语文   |  3 |          3 |  NULL |          1 |
      如上查询所示:当同时查询多表时,多表之间没有有效的的连接条件时,每张表的每行数据都将与另外几张表的每行数据进行关联输出,导致查询结果错误。
      若表1中有5条数据,表2中有20条数据,在同时查询两张表时,结果将会有 5*20=100条数据
      为避免笛卡尔乘积现象的发生,则需要在多表查询时添加有效的连接条件。
      如:
      mysql> select * from subject su,score sc where su.id=sc.subject_id;
      +----+--------+----+------------+-------+------------+
      | id | name   | id | subject_id | score | student_id |
      +----+--------+----+------------+-------+------------+
      |  1 | 语文   |  1 |          1 |    80 |          1 |
      |  2 | 数学   |  2 |          2 |    79 |          1 |
      |  3 | 英语   |  3 |          3 |  NULL |          1 |
      |  1 | 语文   |  6 |          1 |    86 |          2 |
      |  2 | 数学   |  7 |          2 |    97 |          2 |
      |  3 | 英语   |  8 |          3 |    85 |          2 |
      |  1 | 语文   | 11 |          1 |    90 |          3 |
      |  2 | 数学   | 12 |          2 |  NULL |          3 |
      |  3 | 英语   | 13 |          3 |  NULL |          3 |
      |  1 | 语文   | 16 |          1 |  NULL |          4 |
      |  2 | 数学   | 17 |          2 |    87 |          4 |
      |  3 | 英语   | 18 |          3 |    45 |          4 |
      +----+--------+----+------------+-------+------------+
      12 rows in set (0.00 sec)
    

    三、JOIN连接图

    网上找了一张各种JOIN连接查询结果图:

    四、内连接

      内连接有两种语法标准:SQL92标准和SQL99标准 
      SQL92标准语法:
            select 查询列表 from table_name1,table_name2,... where 连接条件 order by 排序规则
      SQL99标准语法:
            select 查询列表 from table_name1 [inner] join table_name2 on 连接条件 [where 查询条件 group by 分组 having 筛选条件 order by 排序规则 limit 分页查询]
      1)等值连接
            #1. 查询学生的各科成绩
            mysql> select st.name 姓名,su.name 科目,sc.score 分数 from students st,subject su,score sc where st.id=sc.student_id and sc.subject_id=su.id;
            mysql> select st.name 姓名,su.name 科目,sc.score 分数 from students st inner join score sc on st.id=sc.student_id join subject su on sc.subject_id=su.id;
            +-----------+--------+-------+
            | 姓名      | 科目   | 分数   |
            +-----------+--------+-------+
            | 张三      | 语文   |     80 |
            | 张三      | 数学   |     79 |
            | 张三      | 英语   |   NULL |
            | 李四      | 语文   |     86 |
            | 李四      | 数学   |     97 |
            | 李四      | 英语   |     85 |
            | 周芷若    | 语文   |     90 |
            | 周芷若    | 数学   |   NULL |
            | 周芷若    | 英语   |   NULL |
            | 赵敏      | 语文   |   NULL |
            | 赵敏      | 数学   |     87 |
            | 赵敏      | 英语   |     45 |
            +-----------+--------+--------+
            12 rows in set (0.00 sec)
    
            #2. 查询有成绩的学生的各科成绩
            mysql> select st.name 姓名,su.name 科目,sc.score 分数 from students st,subject su,score sc where st.id=sc.student_id and sc.subject_id=su.id and sc.score is not null;
            mysql> select st.name 姓名,su.name 科目,sc.score 分数 from students st inner join score sc on st.id=sc.student_id join subject su on sc.subject_id=su.id where sc.score is not null;
            +-----------+--------+--------+
            | 姓名      | 科目   | 分数   |
            +-----------+--------+--------+
            | 张三      | 语文   |     80 |
            | 张三      | 数学   |     79 |
            | 李四      | 语文   |     86 |
            | 李四      | 数学   |     97 |
            | 李四      | 英语   |     85 |
            | 周芷若    | 语文   |     90 |
            | 赵敏      | 数学   |     87 |
            | 赵敏      | 英语   |     45 |
            +-----------+--------+--------+
            8 rows in set (0.00 sec)
      
            #3. 查询每个学生的总成绩,并按总成绩倒序排列
            mysql> select st.name 姓名,sum(sc.score) 总成绩 from students st,score sc where st.id=sc.student_id group by st.name order by 总成绩 desc;
            mysql> select st.name 姓名,sum(sc.score) 总成绩 from students st join score sc on st.id=sc.student_id group by st.name order by 总成绩 desc;
            +-----------+-----------+
            | 姓名      | 总成绩    |
            +-----------+-----------+
            | 李四      |       325 |
            | 张三      |       318 |
            | 赵敏      |       200 |
            | 周芷若    |       150 |
            +-----------+-----------+
            4 rows in set (0.00 sec)
            
      2)非等值连接
            #1. 查询出学生的各科成绩及对应的级别
            mysql> select a.*,b.name 级别 from (select st.name 姓名,su.name 科目,sc.score 分数 from students st inner join score sc on st.id=sc.student_id join subject su on      sc.subject_id=su.id where sc.score is not null) a join grade b on a.分数 between b.min_score and b.max_score;
      +-----------+--------+--------+--------+
      | 姓名      | 科目   | 分数   | 级别   |
      +-----------+--------+--------+--------+
      | 赵敏      | 英语   |     45 | A级    |
      | 张三      | 数学   |     79 | B级    |
      | 赵敏      | 数学   |     87 | C级    |
      | 赵敏      | 语文   |     86 | C级    |
      | 李四      | 英语   |     85 | C级    |
      | 李四      | 语文   |     86 | C级    |
      | 张三      | 语文   |     80 | C级    |
      | 周芷若    | 语文   |     90 | D级    |
      | 李四      | 数学   |     97 | D级    |
      +-----------+--------+--------+--------+
      9 rows in set (0.05 sec)
            
      3)自连接
            #1. 查询出各科成绩前2名的学生姓名,科目,及分数
            select 
                  a.* 
            from 
                  (
                        select 
                              st.name 姓名,su.name 科目,sc.score 成绩 
                        from 
                              students st,subject su,score sc 
                        where 
                              st.id=sc.student_id and su.id=sc.subject_id
                  ) a 
            where 
                  2 > (
                        select 
                              count(*) 
                        from 
                              (
                                    select 
                                          st.name 姓名,su.name 科目,sc.score 成绩 
                                    from 
                                          students st,subject su,score sc 
                                    where 
                                          st.id=sc.student_id and su.id=sc.subject_id
                              ) b 
                        where 
                              b.科目=a.科目 and b.成绩>a.成绩
                  ) 
                  and 
                        a.成绩 is not null
            order by 
                  a.科目, a.成绩 desc;
            +-----------+--------+--------+
            | 姓名      | 科目   | 成绩   |
            +-----------+--------+--------+
            | 李四      | 数学   |     97 |
            | 赵敏      | 数学   |     87 |
            | 李四      | 英语   |     85 |
            | 赵敏      | 英语   |     45 |
            | 周芷若    | 语文   |     90 |
            | 李四      | 语文   |     86 |
            | 赵敏      | 语文   |     86 |
            +-----------+--------+--------+
            7 rows in set (0.00 sec)
    

    二、外连接:

      1)左外连接:
            select 查询列表 from table_name1 left [outer] join table_name2 on 连接条件 [where 查询条件 group by 分组列表 having 筛选条件 order by 分组规则 limit 分页信息]
      例:
            #1. 查询出所有学生各科的成绩
            mysql> select st.*,sc.score,su.name from students st left join score sc on st.id=sc.student_id left join subject su on sc.subject_id=su.id;
            +----+-----------+--------+------+-------+--------+
            | id | name      | gender | age  | score | name   |
            +----+-----------+--------+------+-------+--------+
            |  1 | 张三      |      1 |   18 |    69 | NULL   |
            |  1 | 张三      |      1 |   18 |    90 | NULL   |
            |  1 | 张三      |      1 |   18 |  NULL | 英语   |
            |  1 | 张三      |      1 |   18 |    79 | 数学   |
            |  1 | 张三      |      1 |   18 |    80 | 语文   |
            |  2 | 李四      |      1 |   19 |    57 | NULL   |
            |  2 | 李四      |      1 |   19 |  NULL | NULL   |
            |  2 | 李四      |      1 |   19 |    85 | 英语   |
            |  2 | 李四      |      1 |   19 |    97 | 数学   |
            |  2 | 李四      |      1 |   19 |    86 | 语文   |
            |  3 | 周芷若    |      2 |   18 |    60 | NULL   |
            |  3 | 周芷若    |      2 |   18 |  NULL | NULL   |
            |  3 | 周芷若    |      2 |   18 |  NULL | 英语   |
            |  3 | 周芷若    |      2 |   18 |  NULL | 数学   |
            |  3 | 周芷若    |      2 |   18 |    90 | 语文   |
            |  4 | 赵敏      |      2 |   18 |    68 | NULL   |
            |  4 | 赵敏      |      2 |   18 |  NULL | NULL   |
            |  4 | 赵敏      |      2 |   18 |    45 | 英语   |
            |  4 | 赵敏      |      2 |   18 |    87 | 数学   |
            |  4 | 赵敏      |      2 |   18 |    86 | 语文   |
            |  5 | Lucy      |      2 |   19 |  NULL | NULL   |
            |  6 | Tony      |      1 |   20 |  NULL | NULL   |
            |  7 | Lucy      |      2 |   20 |  NULL | NULL   |
            +----+-----------+--------+------+-------+--------+
            23 rows in set (0.00 sec)
    
    
            #2. 查询出没有参加考试或总成绩为0的学生信息
            mysql> select b.* from (select student_id from score group by student_id having sum(score)>0 and sum(score) is not null) a left join students b on a.student_id=b.id;
            +----+------+--------+------+
            | id | name | gender | age  |
            +----+------+--------+------+
            |  5 | Lucy |      2 |   19 |
            |  6 | Tony |      1 |   20 |
            |  7 | Lucy |      2 |   20 |
            +----+------+--------+------+
            3 rows in set (0.02 sec)
    
            #3. 查询出所有没有成绩的学生信息和没有成绩的科目
            mysql> select st.*,sc.score,su.name from students st left join score sc on st.id=sc.student_id left join subject su on sc.subject_id=su.id where sc.score is null;
            +----+-----------+--------+------+-------+--------+
            | id | name      | gender | age  | score | name   |
            +----+-----------+--------+------+-------+--------+
            |  1 | 张三      |      1 |   18 |  NULL | 英语   |
            |  2 | 李四      |      1 |   19 |  NULL | NULL   |
            |  3 | 周芷若    |      2 |   18 |  NULL | NULL   |
            |  3 | 周芷若    |      2 |   18 |  NULL | 英语   |
            |  3 | 周芷若    |      2 |   18 |  NULL | 数学   |
            |  4 | 赵敏      |      2 |   18 |  NULL | NULL   |
            |  5 | Lucy      |      2 |   19 |  NULL | NULL   |
            |  6 | Tony      |      1 |   20 |  NULL | NULL   |
            |  7 | Lucy      |      2 |   20 |  NULL | NULL   |
            +----+-----------+--------+------+-------+--------+
            
            #4. 查询出每个学生的平均成绩并按平均成绩倒序排列
            mysql> select st.name 姓名, avg(sc.score) 平均成绩 from students st left join score sc on st.id=sc.student_id group by st.name order by 平均成绩 desc;
            +-----------+--------------+
            | 姓名      | 平均成绩     |
            +-----------+--------------+
            | 李四      |      81.2500 |
            | 张三      |      79.5000 |
            | 周芷若    |      75.0000 |
            | 赵敏      |      71.5000 |
            | Lucy      |         NULL |
            | Tony      |         NULL |
            +-----------+--------------+
            6 rows in set (0.07 sec)
    
      2)右外连接语法:
            select 查询列表 from table_name1 right join table_name2 on 连接条件 [where 查询条件 group by 分组列表 having 筛选条件 order by 分组规则 limit 分页信息]
            右外连接和左外连接基本一样,区别在于:
            左外连接left左边的表为主表,右边的表为从表,右外连接与之相反
            如:
            select st.*,sc.score,su.name from score sc right join students st on st.id=sc.student_id left join subject su on sc.subject_id=su.id;
            和左外连接的例1结果相同
      3)全外连接:
            MySQL中不支持full join语法,MySQL中可以使用union连接两个SQL语句,实现全外连接,如:
            select st.*,sc.score from students st left join score sc on st.id=sc.student_id 
            union 
            select st.*,sc.score from students st right join score sc on st.id=sc.student_id;
            +------+-----------+--------+------+-------+
            | id   | name      | gender | age  | score |
            +------+-----------+--------+------+-------+
            |    1 | 张三      |      1 |   18 |    69 |
            |    1 | 张三      |      1 |   18 |    90 |
            |    1 | 张三      |      1 |   18 |  NULL |
            |    1 | 张三      |      1 |   18 |    79 |
            |    1 | 张三      |      1 |   18 |    80 |
            |    2 | 李四      |      1 |   19 |    57 |
            |    2 | 李四      |      1 |   19 |  NULL |
            |    2 | 李四      |      1 |   19 |    85 |
            |    2 | 李四      |      1 |   19 |    97 |
            |    2 | 李四      |      1 |   19 |    86 |
            |    3 | 周芷若    |      2 |   18 |    60 |
            |    3 | 周芷若    |      2 |   18 |  NULL |
            |    3 | 周芷若    |      2 |   18 |    90 |
            |    4 | 赵敏      |      2 |   18 |    68 |
            |    4 | 赵敏      |      2 |   18 |  NULL |
            |    4 | 赵敏      |      2 |   18 |    45 |
            |    4 | 赵敏      |      2 |   18 |    87 |
            |    4 | 赵敏      |      2 |   18 |    86 |
            |    5 | Lucy      |      2 |   19 |  NULL |
            |    6 | Tony      |      1 |   20 |  NULL |
            |    7 | Lucy      |      2 |   20 |  NULL |
            +------+-----------+--------+------+-------+
            21 rows in set (0.00 sec)
    
            union连接可以实现去重。
    

    三、交叉连接:

      语法:
            select 查询列表 from table_name1 cross join table_name2;
      交叉连接结果为笛卡尔乘积。
    

    四、子查询

      出现在其他语句中的select语句,称为子查询
      #1. 查询出没有参加考试或总成绩为0的学生信息
            select * 
            from students 
            where id in 
                  (select student_id from score group by student_id having sum(score)>0 and sum(score) is not null); #子查询
            +----+------+--------+------+
            | id | name | gender | age  |
            +----+------+--------+------+
            |  5 | Lucy |      2 |   19 |
            |  6 | Tony |      1 |   20 |
            |  7 | Lucy |      2 |   20 |
            +----+------+--------+------+
            3 rows in set (0.02 sec)
  • 相关阅读:
    ajax遇到的问题
    Javascript事件传播(冒泡机制) (摘自 博客园 萍水相逢)
    学习的一点体悟和衷告
    localStorag的一点见解
    感谢!
    文件上传的一些方法
    form:form的一点体会
    鼠标事件大汇总
    readonly和disabled的异同
    说说icon图标
  • 原文地址:https://www.cnblogs.com/huige185/p/13995690.html
Copyright © 2011-2022 走看看