Mysql学习笔记(四)——多表查询

Mysql学习笔记(四)——多表查询

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;

    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;

    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;

    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);

    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只会显示符合连接条件的记录

    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; /* 其他限定条件 */

    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;

    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 ');

    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= ‘ 刘三姐 ’);
    此查询为不相关子查询。

    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’
    )
    );

    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);

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

    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 ’ ; /*父查询块中的条件 */

    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 ';

    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 ');

    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’);

    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)
    可以把带有全称量词的谓词转换为等价的带有存在量词的谓词:
    1560671274761

  • 例:[例39]查询与“刘三姐”在同一个系学习的学生。
    可以用带EXISTS谓词的子查询替换:
    SELECT Sno,Sname,Sdept
    FROM Student S1
    WHERE EXISTS
      (SELECT *
    FROM Student S2
    WHERE S2.Sdept = S1.Sdept AND
    S2.Sname = ‘刘三姐’);

    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 —这门课

    );

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”
    则上述查询为: 1560754969021

  • 1560754992046

  • 变换后语义:不存在这样的课程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));—这门课

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:将多个查询结果合并起来时,保留重复元组

    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;

    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 ';

    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;

    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);

    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;

    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;

    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语句最不好搞,作者也没想到好的描述方法,如果有好的方法可以评论共同探讨,如果觉得有帮助的话,请点赞鼓励我更上一层楼!
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值