1.概述

  • 连接查询:同时涉及多个表的查询
    连接条件或连接谓词:用来连接两个表的条件
     一般格式:
    
    [<表名1>.]<列名1> <比较运算符> [<表名2>.]<列名2>
    [<表名1>.]<列名1> BETWEEN [<表名2>.]<列名2> AND [<表名2>.]<列名3>
    连接字段:连接谓词中的列名称
    连接条件中的各连接字段类型必须是可比的,但名字不必是相同的

2.等值和非等值连接

  • 等值连接:连接运算符为=
    [例33] 查询每个学生及其选修课程的情况
    SELECT Student.*,SC.*
    FROM Student,SC
    WHERE Student.Sno = SC.Sno;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    mysql> select student.*,sc.* from student,sc where Student.Sno = sc.Sno;
    +-------+-----------+------+------+-------+-------+-----+-------+
    | Sno | Sname | Ssex | Sage | Sdept | Sno | Cno | Grade |
    +-------+-----------+------+------+-------+-------+-----+-------+
    | 95001 | 张三 | 男 | 21 | CS | 95001 | 1 | 93 |
    | 95001 | 张三 | 男 | 21 | CS | 95001 | 2 | 95 |
    | 95001 | 张三 | 男 | 21 | CS | 95001 | 3 | 91 |
    | 95001 | 张三 | 男 | 21 | CS | 95001 | 4 | 98 |
    | 95002 | 李四 | 男 | 23 | IS | 95002 | 2 | 90 |
    | 95002 | 李四 | 男 | 23 | IS | 95002 | 3 | 80 |
    | 95003 | 王五 | 男 | 19 | MA | 95003 | 2 | NULL |
    | 95004 | 马六 | 女 | 20 | CS | 95004 | 3 | NULL |
    | 95004 | 马六 | 女 | 20 | CS | 95004 | 4 | 88 |
    | 95005 | 苏三 | 女 | 20 | IS | 95005 | 1 | 90 |
    | 95005 | 苏三 | 女 | 20 | IS | 95005 | 2 | 98 |
    | 95005 | 苏三 | 女 | 20 | IS | 95005 | 3 | 90 |
    | 95005 | 苏三 | 女 | 20 | IS | 95005 | 4 | 89 |
    | 95011 | 张成民 | 男 | 19 | CS | 95011 | 1 | NULL |
    +-------+-----------+------+------+-------+-------+-----+-------+
    14 rows in set (0.01 sec)

    此时发现表中有两竖列的值是相同的,所以是冗余的。

  • 自然连接:

    [例34] 对上例用自然连接完成。
    SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
    FROM Student,SC
    WHERE Student.Sno = SC.Sno;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    mysql> select student.Sno,Sname,Ssex,Sage,Sdept,cno,Grade from student,sc where Student.Sno=sc.sno;
    +-------+-----------+------+------+-------+-----+-------+
    | Sno | Sname | Ssex | Sage | Sdept | cno | Grade |
    +-------+-----------+------+------+-------+-----+-------+
    | 95001 | 张三 | 男 | 21 | CS | 1 | 93 |
    | 95001 | 张三 | 男 | 21 | CS | 2 | 95 |
    | 95001 | 张三 | 男 | 21 | CS | 3 | 91 |
    | 95001 | 张三 | 男 | 21 | CS | 4 | 98 |
    | 95002 | 李四 | 男 | 23 | IS | 2 | 90 |
    | 95002 | 李四 | 男 | 23 | IS | 3 | 80 |
    | 95003 | 王五 | 男 | 19 | MA | 2 | NULL |
    | 95004 | 马六 | 女 | 20 | CS | 3 | NULL |
    | 95004 | 马六 | 女 | 20 | CS | 4 | 88 |
    | 95005 | 苏三 | 女 | 20 | IS | 1 | 90 |
    | 95005 | 苏三 | 女 | 20 | IS | 2 | 98 |
    | 95005 | 苏三 | 女 | 20 | IS | 3 | 90 |
    | 95005 | 苏三 | 女 | 20 | IS | 4 | 89 |
    | 95011 | 张成民 | 男 | 19 | CS | 1 | NULL |
    +-------+-----------+------+------+-------+-----+-------+
    14 rows in set (0.00 sec)

    这里一定要注意选择的时候要用Student.Sno,不能单独只写一个sno,因为连接的两个表都有sno,这时区分不开到底是哪个。

3.自身连接

  • 自身连接:一个表与其自己进行连接
    需要给表起别名以示区别
    由于所有属性名都是同名属性,因此必须使用别名前缀

    [例35]查询每一门课的间接先修课(即先修课的先修课)

    SELECT  FIRST.Cno,SECOND.Cpno
     FROM  Course  FIRST,Course  SECOND
     WHERE FIRST.Cpno = SECOND.Cno;
    
    1
    2
    3
    4
    5
    6
    7
    8
    mysql> select First.Cno,Second.Cpno from Course First,Course Second where first.cpno = second.cno;
    +-----+------+
    | Cno | Cpno |
    +-----+------+
    | 2 | 4 |
    | 3 | NULL |
    +-----+------+
    2 rows in set (0.01 sec)

4.外连接

  • 外连接与普通连接的区别
    普通连接操作只输出满足连接条件的元组
    外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出
    [例 36] 改写[例35]
    SELECT FIRST.Cno, SECOND.Cpno FROM Course FIRST LEFT JOIN Course SECOND ON (FIRST.Cpno=SECOND.Cno);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    mysql> select First.Cno,Second.Cpno from Course First LEFT JOIN Course Second ON(first.cpno = second.cno);
    +-----+------+
    | Cno | Cpno |
    +-----+------+
    | 2 | 4 |
    | 3 | NULL |
    | 1 | NULL |
    | 4 | NULL |
    +-----+------+
    4 rows in set (0.00 sec)
  • 左外连接LEFT JOIN
    列出左边关系中所有的元组
    右外连接RIGHT JOIN
    列出右边关系中所有的元组
    SELECT * FROM Course FIRST RIGHT JOIN Course SECOND ON (FIRST.Cpno=SECOND.Cno);

    A left join B: 是以A表的记录为基础的,A的每一条记录依次和B连接,A的记录将会全部表示出来,而B只会显示符合连接条件的记录.
    A right join B: 是以B表的记录为基础的,B的每一条记录依次和A连接,B的记录将会全部表示出来,而A只会显示符合连接条件的记录

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    mysql> select First.Cno,Second.Cpno from Course First RIGHT JOIN Course Second ON(first.cpno = second.cno);
    +------+------+
    | Cno | Cpno |
    +------+------+
    | 2 | 4 |
    | 3 | NULL |
    | NULL | NULL |
    | NULL | 3 |
    +------+------+
    4 rows in set (0.00 sec)

5.复合条件连接

  • 复合条件连接:WHERE子句中含多个连接条件
    [例37]查询选修2号课程且成绩在90分以上的所有学生的学号和姓名

    SELECT Student.Sno, Sname
    FROM    Student, SC
    WHERE Student.Sno = SC.Sno AND /* 连接谓词*/
        Cno= ‘2’ AND Grade > 90;   /* 其他限定条件 */
    
    1
    2
    3
    4
    5
    6
    7
    8
    mysql> select Student.sno,sname from student,sc where student.Sno = sc.Sno AND Cno='2' AND Grade >90;
    +-------+--------+
    | sno | sname |
    +-------+--------+
    | 95001 | 张三 |
    | 95005 | 苏三 |
    +-------+--------+
    2 rows in set (0.01 sec)

    该查询的过程是,先从SC表中挑选出Cno=’2’并且Grade>90 的元组形成一个中间关系,再和Student中满足连接条件的元组进行连接得到最终的结果关系。

  • [例38]查询每个学生的学号、姓名、选修的课程名及成绩
    SELECT Student.Sno,Sname,Cname,Grade
    FROM Student,SC,Course /多表连接/
    WHERE Student.Sno = SC.Sno

                 and SC.Cno = Course.Cno;
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    mysql> select student.sno,sname,cname,grade from student,sc,course where student.sno=sc.sno AND sc.cno=course.cno;
    +-------+-----------+-----------+-------+
    | sno | sname | cname | grade |
    +-------+-----------+-----------+-------+
    | 95001 | 张三 | MATH | 93 |
    | 95005 | 苏三 | MATH | 90 |
    | 95011 | 张成民 | MATH | NULL |
    | 95001 | 张三 | DB_DESIGN | 95 |
    | 95002 | 李四 | DB_DESIGN | 90 |
    | 95003 | 王五 | DB_DESIGN | NULL |
    | 95005 | 苏三 | DB_DESIGN | 98 |
    | 95001 | 张三 | P_DESIGN | 91 |
    | 95002 | 李四 | P_DESIGN | 80 |
    | 95004 | 马六 | P_DESIGN | NULL |
    | 95005 | 苏三 | P_DESIGN | 90 |
    | 95001 | 张三 | OS | 98 |
    | 95004 | 马六 | OS | 88 |
    | 95005 | 苏三 | OS | 89 |
    +-------+-----------+-----------+-------+

7.嵌套查询

  • 嵌套查询概述
    一个SELECT-FROM-WHERE语句称为一个查询块
    将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询称为嵌套查询

  • 子查询的限制
    不能使用ORDER BY子句,order by 子句只能对最终查询结果进行排序
    层层嵌套方式反映了 SQL语言的结构化
    有些嵌套查询可以用连接运算替代

  • SELECT Sname /外层查询/父查询/
    FROM Student
    WHERE Sno IN
    (SELECT Sno /内层查询/子查询/
    FROM SC
    WHERE Cno= ‘ 2 ‘);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    mysql> select Sname from student where sno IN (select sno from sc where cno='2');
    +--------+
    | Sname |
    +--------+
    | 张三 |
    | 李四 |
    | 王五 |
    | 苏三 |
    +--------+

    先查询选修课程号为2的学生学号,之后再在student中查询满足学号的学生姓名

  • 不相关子查询:

    查询的查询条件不依赖于父查询
    

    由里向外逐层处理。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。

  • 相关子查询:子查询的查询条件依赖于父查询
    首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表
    然后再取外层表的下一个元组
    重复这一过程,直至外层表全部检查完为止

A 带有IN谓词的子查询

  • [例39] 查询与“刘三姐”在同一个系学习的学生。

    此查询要求可以分步来完成
    

    ① 确定“刘三姐”所在系名

    SELECT  Sdept  
     FROM     Student                            
     WHERE  Sname= ‘ 刘三姐 ';
          结果为: IS
    

    ② 查找所有在IS系学习的学生。

        SELECT   Sno,Sname,Sdept     
        FROM      Student                 
        WHERE  Sdept= ‘ IS’; 
    

    将第一步查询嵌入到第二步查询的条件中

    SELECT Sno,Sname,Sdept
        FROM Student
       WHERE Sdept  IN
                  (SELECT Sdept
                   FROM Student
                   WHERE Sname= ‘ 刘三姐 ’);
    此查询为不相关子查询。
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    mysql> select Sno,Sname,Sdept from Student where Sdept IN (select Sdept from Student where Sname ='刘三姐');
    +-------+-----------+-------+
    | Sno | Sname | Sdept |
    +-------+-----------+-------+
    | 95002 | 李四 | IS |
    | 95005 | 苏三 | IS |
    | 95006 | 刘七 | IS |
    | 95007 | 刘三姐 | IS |
    | 95010 | 陈东 | IS |
    +-------+-----------+-------+
    5 rows in set (0.00 sec)
  • [例40]查询选修了课程名为“DB_DESIGN”的学生学号和姓名
    SELECT Sno,Sname ③ 最后在Student关系中
    FROM Student 取出Sno和Sname
    WHERE Sno IN

        (SELECT Sno                         ② 然后在SC关系中找出选
         FROM    SC                           修了2号课程的学生学号
         WHERE  Cno IN
               (SELECT Cno               ① 首先在Course关系中找出
                 FROM Course            “DB_DESIGN”的课程号,为2号
                 WHERE Cname= ‘DB_DESIGN’
               )
         );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    mysql> select Sno,Sname from Student where Sno IN (select Sno from sc where Cno IN (select Cno from Course where cname='DB_DES
    IGN'));
    +-------+--------+
    | Sno | Sname |
    +-------+--------+
    | 95001 | 张三 |
    | 95002 | 李四 |
    | 95003 | 王五 |
    | 95005 | 苏三 |
    +-------+--------+
    4 rows in set (0.00 sec)

B 带有比较运算符的子查询

  • 当能确切知道内层查询返回单值时,可用比较运算符(>,<,=,>=,<=,!=或< >)。
    与ANY或ALL谓词配合使用

  • [例41]找出每个学生超过他选修课程平均成绩的课程号和学号。
    SELECT Sno, Cno
    FROM SC x
    WHERE Grade >(SELECT AVG(Grade)

               FROM  SC y
               WHERE y.Sno=x.Sno);
    

    子查询一定要跟在比较符之后

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    mysql> select Sno,Cno from sc x where Grade >(select AVG(Grade) from sc y where y.sno=x.sno);
    +-------+-----+
    | Sno | Cno |
    +-------+-----+
    | 95001 | 2 |
    | 95001 | 4 |
    | 95002 | 2 |
    | 95005 | 2 |
    +-------+-----+
    4 rows in set (0.00 sec)
    1. 从外层查询中取出SC的一个元组x,将元组x的Sno值(95001)传送给内层查询。
      SELECT AVG(Grade)
      FROM SC y
      WHERE y.Sno=‘95001’;
    2. 执行内层查询,得到值93(近似值),用该值代替内层查询,得到外层查询:
      SELECT Sno, Cno
      FROM SC x
      WHERE Grade >93;
    3. 执行这个查询,得到
      (95001,2)
      (95001,4)
    4. 外层查询取出下一个元组重复做上述1至3步骤,直到外层的SC元组全部处理完毕。

C.带有ANY(SOME)或ALL谓词的子查询

  • 谓词语义
    ANY:任意一个值(只要有一个值)
    ALL:所有值

  • 需要配合使用比较运算符

    >ANY 大于子查询结果中的某个值
    >ALL 大于子查询结果中的所有值
    < ANY 小于子查询结果中的某个值
    < ALL 小于子查询结果中的所有值
    >= ANY 大于等于子查询结果中的某个值
    >= ALL 大于等于子查询结果中的所有值
    <= ANY 小于等于子查询结果中的某个值
    <= ALL 小于等于子查询结果中的所有值
    = ANY 等于子查询结果中的某个值
    =ALL 等于子查询结果中的所有值(通常没有实际意义)
    !=(或<>)ANY 不等于子查询结果中的某个值
    !=(或<>)ALL 不等于子查询结果中的任何一个值

  • [例42] 查询其他系中比计算机科学某一学生年龄小的学生姓名和年龄

    SELECT Sname,Sage
    FROM    Student
    WHERE Sage < ANY (SELECT  Sage
                      FROM    Student
                      WHERE Sdept= ' CS ')
           AND Sdept <> ‘CS ' ;           /*父查询块中的条件 */
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    mysql> select Sname,Sage from student where Sage < ANY (select Sage from student where Sdept ='CS') AND Sdept <>'CS';
    +--------+------+
    | Sname | Sage |
    +--------+------+
    | 王五 | 19 |
    | 苏三 | 20 |
    | 刘七 | 19 |
    | 陈东 | 19 |
    +--------+------+
    4 rows in set (0.00 sec)

    执行过程:
    1.RDBMS执行此查询时,首先处理子查询,找出
    CS系中所有学生的年龄,构成一个集合(21,19)

    1. 处理父查询,找所有不是CS系且年龄小于
      21 或 19的学生
  • 用聚集函数实现[例42]

    SELECT Sname,Sage
    FROM Student
    WHERE Sage < (SELECT MAX(Sage)

               FROM Student
               WHERE Sdept= ‘CS ')
       AND Sdept <> ' CS ';
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    mysql> select Sname,Sage from student where Sage <(select MAX(Sage) from student where Sdept ='CS') AND Sdept <>'CS';
    +--------+------+
    | Sname | Sage |
    +--------+------+
    | 王五 | 19 |
    | 苏三 | 20 |
    | 刘七 | 19 |
    | 陈东 | 19 |
    +--------+------+
    4 rows in set (0.00 sec)
  • [例43] 查询其他系中比计算机科学系所有学生年龄都小的学生姓名及年龄。

    方法一:用ALL谓词

    SELECT Sname,Sage
    FROM Student
    WHERE Sage < ALL(SELECT Sage
                     FROM Student
                     WHERE Sdept= ' CS ')
        AND Sdept <> ' CS ';
    

    方法二:用聚集函数

    SELECT Sname,Sage
    FROM Student
    WHERE Sage <(SELECT MIN(Sage)
                 FROM Student
                 WHERE Sdept= ' CS ')
          AND Sdept <>' CS ’;
    

D 带有EXISTS谓词的子查询

  • EXISTS谓词
    存在量词
    带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true”或逻辑假值“false”。
    若内层查询结果非空,则外层的WHERE子句返回真值
    若内层查询结果为空,则外层的WHERE子句返回假值
    由EXISTS引出的子查询,其目标列表达式通常都用* ,因为带EXISTS的子查询只返回真值或假值,给出列名无实际意义

  • NOT EXISTS谓词
    若内层查询结果非空,则外层的WHERE子句返回假值
    若内层查询结果为空,则外层的WHERE子句返回真值

  • [例44]查询所有选修了1号课程的学生姓名。

    思路分析:
    本查询涉及Student和SC关系
    在Student中依次取每个元组的Sno值,用此值去检查SC关系
    若SC中存在这样的元组,其Sno值等于此Student.Sno值,并且其Cno= ‘1’,则取此Student.Sname送入结果关系

    用嵌套查询

     SELECT Sname
     FROM Student
     WHERE EXISTS
                 (SELECT *
                  FROM SC
                  WHERE Sno=Student.Sno AND Cno= ' 1 ');
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    mysql> select Sname from Student where EXISTS(select * from sc where Sno=student.sno AND Cno='1');
    +-----------+
    | Sname |
    +-----------+
    | 张三 |
    | 苏三 |
    | 张成民 |
    +-----------+
    3 rows in set (0.00 sec)

    用连接做

    SELECT Sname
    FROM Student, SC
    WHERE Student.Sno=SC.Sno AND SC.Cno= ‘1’;

  • [例45] 查询没有选修1号课程的学生姓名。

    SELECT Sname
    FROM Student
    WHERE NOT EXISTS
                  (SELECT *
                   FROM SC
                   WHERE Sno = Student.Sno AND Cno='1');
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    mysql> select Sname from student where NOT EXISTS(select * from sc where sno=student.sno AND Cno='1');
    +--------------+
    | Sname |
    +--------------+
    | 李四 |
    | 王五 |
    | 马六 |
    | 刘七 |
    | 刘三姐 |
    | 欧阳锋 |
    | 欧阳大侠 |
    | 陈东 |
    +--------------+
  • 不同形式的查询间的替换
    一些带EXISTS或NOT EXISTS谓词的子查询不能被其他形式的子查询等价替换
    所有带IN谓词、比较运算符、ANY和ALL谓词的子查询都能用带EXISTS谓词的子查询等价替换
    用EXISTS/NOT EXISTS实现全称量词(难点)
    SQL语言中没有全称量词 (For all)
    可以把带有全称量词的谓词转换为等价的带有存在量词的谓词:
  • 例:[例39]查询与“刘三姐”在同一个系学习的学生。

    可以用带EXISTS谓词的子查询替换:
    

    SELECT Sno,Sname,Sdept
    FROM Student S1
    WHERE EXISTS

              (SELECT *
                  FROM Student S2
                  WHERE S2.Sdept = S1.Sdept AND
                                S2.Sname = ‘刘三姐’);
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    mysql> select Sno,Sname,Sdept from Student S1 where exists (select * from student S2 where
    S1.sdept=S2.sdept AND S2.Sname='刘三姐');
    +-------+-----------+-------+
    | Sno | Sname | Sdept |
    +-------+-----------+-------+
    | 95002 | 李四 | IS |
    | 95005 | 苏三 | IS |
    | 95006 | 刘七 | IS |
    | 95007 | 刘三姐 | IS |
    | 95010 | 陈东 | IS |
    +-------+-----------+-------+
    6 rows in set (2.33 sec)
  • [例46] 查询选修了全部课程的学生姓名。
    查询这样的学生,没有一门课是他不选的。

     SELECT Sname
     FROM Student
     WHERE NOT EXISTS     -----不存在 
        (SELECT *  FROM Course   ----有这样一条记录(有这样一门课)
    

    —-这个学生没有选这门课(不存在这样一门课,这个学生选了的)

              WHERE NOT EXISTS           ----不存在   
                        (SELECT *
                         FROM SC
                         WHERE Sno= Student.Sno  ---这个学生 
                         AND Cno= Course.Cno   ---这门课 
                       )
                 );
    
1
2
3
4
5
6
7
8
9
mysql> select Sname from student where NOT EXISTS(select * from COurse where NOT EXISTS (select * from sc where Sno=student.sno AND CNO=course.Cno));
+--------+
| Sname |
+--------+
| 张三 |
| 苏三 |
+--------+
2 rows in set (0.01 sec)

  • [例47]查询至少选修了学生95002选修的全部课程的学生号码。(除运算)
    解题思路:
    用逻辑蕴函表达:查询学号为x的学生,对所有的课程y,只要95002学生选修了课程y,则x也选修了y。
    形式化表示:
    用p表示谓词 “学生95002选修了课程y”
    用q表示谓词 “学生x选修了课程y”
    
  • 变换后语义:不存在这样的课程y,学生95002选修了y,而学生x没有选。

用NOT EXISTS谓词表示:
SELECT DISTINCT Sno
FROM SC SCX
WHERE NOT EXISTS ——-不存在
(SELECT
FROM SC SCY ——有95002选的一门课
WHERE SCY.Sno = ‘ 95002 ‘ AND
—-这个学生没有选95002选的这门课
NOT EXISTS ——-不存在
(SELECT

FROM SC SCZ ——有这样一条选课记录
WHERE SCZ.Sno=SCX.Sno —-这个学生
AND SCZ.Cno=SCY.Cno));—-这门课

首先选出x的第一行,和y的95002的数据的第一行,来判断第三张表z中的课程是否和y的第一行课程一样,如果一样则表明存在,NOT EXISTS为假,继续判断95002的第二行在第三张表中是否存在,如果不存在,那就为真,上面的NOT EXISTS就为假,这个学号不输出

1
2
3
4
5
6
7
8
9
10
11
mysql> select DISTINCT SNO from SC scx where NOT EXISTS(select * from sc scy where scy.Sno
='95002' AND NOT EXISTS(select * from sc scz where scz.Sno=scx.sno AND scz.cno=scy.cno));
+-------+
| SNO |
+-------+
| 95001 |
| 95002 |
| 95005 |
+-------+
3 rows in set (0.01 sec)

8.集合查询

  • 集合操作的种类
    并操作UNION
    交集

    笛卡尔积
    参加集合操作的各查询结果的列数必须相同;对应项的数据类型也必须相同

  • [例48] 查询计算机科学系的学生及年龄不大于19岁的学生。
    方法一:

        SELECT *
        FROM Student
        WHERE Sdept= 'CS'
        UNION
        SELECT *
        FROM Student
        WHERE Sage<=19;
    

    UNION:将多个查询结果合并起来时,系统自动去掉重复元组。
    UNION ALL:将多个查询结果合并起来时,保留重复元组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    mysql> select * from student where sdept ='CS' UNION select * from student where Sage<=19;

    +-------+-----------+------+------+-------+
    | Sno | Sname | Ssex | Sage | Sdept |
    +-------+-----------+------+------+-------+
    | 95001 | 张三 | 男 | 21 | CS |
    | 95004 | 马六 | 女 | 20 | CS |
    | 95011 | 张成民 | 男 | 19 | CS |
    | 95003 | 王五 | 男 | 19 | MA |
    | 95006 | 刘七 | 女 | 19 | IS |
    | 95010 | 陈东 | 男 | 19 | IS |
    +-------+-----------+------+------+-------+
    6 rows in set (0.00 sec)

  • 方法二:用多重条件查询

    SELECT DISTINCT *
    FROM Student
    WHERE Sdept= ‘CS’ OR Sage<=19;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    mysql> select DISTINCT * from Student where sdept ='CS' OR Sage<=19;
    +-------+-----------+------+------+-------+
    | Sno | Sname | Ssex | Sage | Sdept |
    +-------+-----------+------+------+-------+
    | 95001 | 张三 | 男 | 21 | CS |
    | 95003 | 王五 | 男 | 19 | MA |
    | 95004 | 马六 | 女 | 20 | CS |
    | 95006 | 刘七 | 女 | 19 | IS |
    | 95010 | 陈东 | 男 | 19 | IS |
    | 95011 | 张成民 | 男 | 19 | CS |
    +-------+-----------+------+------+-------+
    6 rows in set (0.00 sec)

  • [例49] 查询选修了课程1或者选修了课程2的学生。

    SELECT Sno
    FROM SC
    WHERE Cno=’ 1 ‘
    UNION
    SELECT Sno
    FROM SC
    WHERE Cno= ‘ 2 ‘;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    mysql> select Sno from SC where Cno='1' UNION select Sno from SC where Cno='2';
    +-------+
    | Sno |
    +-------+
    | 95001 |
    | 95005 |
    | 95011 |
    | 95002 |
    | 95003 |
    +-------+
    5 rows in set (0.00 sec)

  • [例50] 查询计算机科学系的学生与年龄不大于19岁的学生的交集

    SELECT * FROM Student WHERE Sdept=’CS’ AND Sage<=19;

    1
    2
    3
    4
    5
    6
    7
    8
    mysql> select * from student where sdept = 'CS' AND Sage<=19;
    +-------+-----------+------+------+-------+
    | Sno | Sname | Ssex | Sage | Sdept |
    +-------+-----------+------+------+-------+
    | 95011 | 张成民 | 男 | 19 | CS |
    +-------+-----------+------+------+-------+
    1 row in set (0.00 sec)

    这里实际上要用到交集INTERSECT,但是和前面多个条件查询一样所以就没有用INTERSECT关键词。

  • [例51] 查询选修课程1的学生集合与选修课程2的学生集合的交集

    SELECT Sno FROM SC WHERE Cno=1
    AND Sno IN (SELECT Sno FROM SC
    WHERE Cno=2);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    mysql> select Sno from sc where cno='1' and sno IN(select sno from sc where cno='2');
    +-------+
    | Sno |
    +-------+
    | 95001 |
    | 95005 |
    +-------+
    2 rows in set (0.00 sec)

  • [例52] 查询计算机科学系的学生与年龄不大于19岁的学生的差集。

    SELECT * FROM Student WHERE Sdept=’CS’ AND Sage>19;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    mysql> select * from student where sdept ='CS' AND sage>19;
    +-------+--------+------+------+-------+
    | Sno | Sname | Ssex | Sage | Sdept |
    +-------+--------+------+------+-------+
    | 95001 | 张三 | 男 | 21 | CS |
    | 95004 | 马六 | 女 | 20 | CS |
    +-------+--------+------+------+-------+
    2 rows in set (0.00 sec)

  • [例52] 查询学生表与课程表的笛卡尔积。

    SELECT * FROM Student CROSS JOIN Course;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    mysql> select * from student CROSS JOIN course;
    +-------+--------------+------+------+-------+-----+-----------+------+---------+
    | Sno | Sname | Ssex | Sage | Sdept | Cno | Cname | Cpno | Ccredit |
    +-------+--------------+------+------+-------+-----+-----------+------+---------+
    | 95001 | 张三 | 男 | 21 | CS | 1 | MATH | NULL | 6 |
    | 95001 | 张三 | 男 | 21 | CS | 2 | DB_DESIGN | 3 | 2 |
    | 95001 | 张三 | 男 | 21 | CS | 3 | P_DESIGN | 4 | 3 |
    | 95001 | 张三 | 男 | 21 | CS | 4 | OS | NULL | 2 |
    | 95002 | 李四 | 男 | 23 | IS | 1 | MATH | NULL | 6 |
    | 95002 | 李四 | 男 | 23 | IS | 2 | DB_DESIGN | 3 | 2 |
    | 95002 | 李四 | 男 | 23 | IS | 3 | P_DESIGN | 4 | 3 |
    | 95002 | 李四 | 男 | 23 | IS | 4 | OS | NULL | 2 |
    | 95003 | 王五 | 男 | 19 | MA | 1 | MATH | NULL | 6 |
    | 95003 | 王五 | 男 | 19 | MA | 2 | DB_DESIGN | 3 | 2 |
    | 95003 | 王五 | 男 | 19 | MA | 3 | P_DESIGN | 4 | 3 |
    | 95003 | 王五 | 男 | 19 | MA | 4 | OS | NULL | 2 |
    | 95004 | 马六 | 女 | 20 | CS | 1 | MATH | NULL | 6 |
    | 95004 | 马六 | 女 | 20 | CS | 2 | DB_DESIGN | 3 | 2 |
    | 95004 | 马六 | 女 | 20 | CS | 3 | P_DESIGN | 4 | 3 |
    | 95004 | 马六 | 女 | 20 | CS | 4 | OS | NULL | 2 |
    | 95005 | 苏三 | 女 | 20 | IS | 1 | MATH | NULL | 6 |
    | 95005 | 苏三 | 女 | 20 | IS | 2 | DB_DESIGN | 3 | 2 |
    | 95005 | 苏三 | 女 | 20 | IS | 3 | P_DESIGN | 4 | 3 |
    | 95005 | 苏三 | 女 | 20 | IS | 4 | OS | NULL | 2 |
    | 95006 | 刘七 | 女 | 19 | IS | 1 | MATH | NULL | 6 |
    | 95006 | 刘七 | 女 | 19 | IS | 2 | DB_DESIGN | 3 | 2 |
    | 95006 | 刘七 | 女 | 19 | IS | 3 | P_DESIGN | 4 | 3 |
    | 95006 | 刘七 | 女 | 19 | IS | 4 | OS | NULL | 2 |
    | 95007 | 刘三姐 | 女 | 23 | IS | 1 | MATH | NULL | 6 |
    | 95007 | 刘三姐 | 女 | 23 | IS | 2 | DB_DESIGN | 3 | 2 |
    | 95007 | 刘三姐 | 女 | 23 | IS | 3 | P_DESIGN | 4 | 3 |
    | 95007 | 刘三姐 | 女 | 23 | IS | 4 | OS | NULL | 2 |
    | 95008 | 欧阳锋 | 男 | 24 | MA | 1 | MATH | NULL | 6 |
    | 95008 | 欧阳锋 | 男 | 24 | MA | 2 | DB_DESIGN | 3 | 2 |
    | 95008 | 欧阳锋 | 男 | 24 | MA | 3 | P_DESIGN | 4 | 3 |
    | 95008 | 欧阳锋 | 男 | 24 | MA | 4 | OS | NULL | 2 |
    | 95009 | 欧阳大侠 | 男 | 23 | MA | 1 | MATH | NULL | 6 |
    | 95009 | 欧阳大侠 | 男 | 23 | MA | 2 | DB_DESIGN | 3 | 2 |
    | 95009 | 欧阳大侠 | 男 | 23 | MA | 3 | P_DESIGN | 4 | 3 |
    | 95009 | 欧阳大侠 | 男 | 23 | MA | 4 | OS | NULL | 2 |
    | 95010 | 陈东 | 男 | 19 | IS | 1 | MATH | NULL | 6 |
    | 95010 | 陈东 | 男 | 19 | IS | 2 | DB_DESIGN | 3 | 2 |
    | 95010 | 陈东 | 男 | 19 | IS | 3 | P_DESIGN | 4 | 3 |
    | 95010 | 陈东 | 男 | 19 | IS | 4 | OS | NULL | 2 |
    | 95011 | 张成民 | 男 | 19 | CS | 1 | MATH | NULL | 6 |
    | 95011 | 张成民 | 男 | 19 | CS | 2 | DB_DESIGN | 3 | 2 |
    | 95011 | 张成民 | 男 | 19 | CS | 3 | P_DESIGN | 4 | 3 |
    | 95011 | 张成民 | 男 | 19 | CS | 4 | OS | NULL | 2 |
    +-------+--------------+------+------+-------+-----+-----------+------+---------+
    48 rows in set (0.00 sec)

  • 插入-子查询

    更新-子查询

    删除-子查询

    • INTO子句(与插入元组类似)

      子查询
      SELECT子句目标列必须与INTO子句匹配
      值的个数
      值的类型

  • [例53] 对每一个系,求学生的平均年龄,并把结果存入数据库。

    第一步:建表

      CREATE  TABLE  Dept_age
          (Sdept  CHAR(15)               /* 系名*/
           Avg_age SMALLINT);       /*学生平均年龄*/
    

    第二步:插入数据

        INSERT
         INTO  Dept_age(Sdept,Avg_age)
              SELECT  Sdept,AVG(Sage)
              FROM  Student
              GROUP BY Sdept;                                      
    
  • [例54] 将计算机科学系全体学生的成绩加1。

    UPDATE SC
    SET  Grade=Grade+1
    WHERE  'CS'=
                   (SELECT Sdept
                    FROM  Student
                    WHERE  Student.Sno = SC.Sno);
    
  • [例55] 删除计算机科学系中没有成绩的学生的选课记录。

    DELETE FROM SC WHERE ‘CS’=(SELECT Sdept FROM Student WHERE Student.Sno=SC.Sno)
    and grade is null;

9.结尾

  • 本篇文章主要讲了多表查询的操作,其中EXSIST语句最不好搞,作者也没想到好的描述方法,如果有好的方法可以评论共同探讨,如果觉得有帮助的话,请点赞鼓励我更上一层楼!