前言
在前文中,我们开始介绍了多表查询,即连接查询,同时简单的介绍了其中的一种形式,即等值连接查询与非等值连接查询,接下来我们将进行介绍连接查询中的另外几种常见形式。此外,本文还将介绍一些见到的嵌套查询以及集合查询。
注:本文中所涉及的数据库前文中已经介绍(指路:数据库系统概论|第三章:关系数据库标准语言SQL—课程笔记1)
一、连接查询
1.等值连接与非等值连接
前文已经进行了介绍(指路:数据库系统概论|第三章:关系数据库标准语言SQL—课程笔记4)
2.自身连接
连接操作不仅可以用于进行两个表之间的连接,同时也可以是一个表与其自己进行连接,此为表的自身连接。
SELECT FIRST.Cname, SECOND.Cname
FROM Course FIRST, Course SECOND
WHERE FIRST.Cpno = SECOND.Cno
上述代码便体现了如何在Course表中查询每一门课的间接先行课(即先行课中的先行课)【此代码中要注意自身连接中,要重读利用统一关系表,分别将原表命名为FIRST与SECOND,此后,再次进行对于这两个表的操作】
3.外连接
普通连接操作只输出满足连接条件的元组。外连接操作除返回满足连接条件的元组外,将主体表中不满足连接条件的元组也一并输出【空位用NULL值填充】。
- 左外连接(LEFT (OUTER) JOIN ):将左表中不满足连接条件的元组也一并输出 。
- 右外连接(RIGHT (OUTER) JOIN ) :将右表中不满足连接条件的元组也一并输出 。
- 完整外部联接(FULL (OUTER) JOIN ):两个表不满足连接条件的元组也一并输出 。
SELECT Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade
FROM Student LEFT OUTER JOIN SC ON (Student.Sno = SC.Sno)
上述代码便体现了用左连接求每个学生的课程选修情况【上述结果中便保留了没有进行选课的同学】
如上图所示,王敏和张立的选课情况中,便显示为NULL值。
SELECT Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade
FROM Student FULL OUTER JOIN SC ON (Student.Sno = SC.Sno)
上述代码便体现了用全外连接求每个学生的课程选修情况【即左右两侧均可能有空值NULL的出现】
4.多表连接
除了上文中体现了量表连接以及自身连接之外,还可以是两表及两表以上的多表连接,其基本语句与上述查询相差不大
SELECT Student.Sno, Sname, Cname, Grade
FROM Student, SC, Course
WHERE Student.Sno = SC.Sno AND SC.Cno = Course.Cno
上述代码便体现了将我们所创建的三个基本表进行了总的连接
二、嵌套查询
一个SELECT-FROM-WHERE语句被称之为一个查询块,一个查询块嵌套在另一个查询块中的查询被称之为嵌套查询,此时,上层查询被称之为外层查询或者父查询,下层查询被称之为内层查询或者子查询。注:子查询的SELECT语句中不可以使用ORDER BY语句!
/*外层查询/父查询*/
SELECT Sname
FROM Student
WHERE Sno IN(
/*内层查询/子查询*/
SELECT Sno
FROM SC
WHERE Cno = '2')
上述代码便体现了查询所有选修了课程2的学生的姓名【内外层查询分别分开,这里将子查询的查询结果作为了一个集合,并利用IN语句进行判断与选择】
——有关EXISTS子句的介绍
带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true”或逻辑假值“false”。
- 若内层查询结果非空,则外层的WHERE子句返回真值;
- 若内层查询结果为空,则外层的WHERE子句返回假值。
--求同时选修了1号和2号课程的学生学号
SELECT Sno FROM SC AS OUT WHERE Cno = '1'
AND EXISTS(SELECT * FROM SC WHERE OUT.Sno = SC.Sno AND Cno = '2' )
--求选修了1号但未选修2号课程的学生学号
SELECT * FROM SC AS OUT WHERE Cno = '1'
AND NOT EXISTS(SELECT * FROM SC WHERE OUT.Sno = SC.Sno AND Cno = '2' )
上述代码分别体现了EXISTS与NOT EXISTS语句的基本使用法则【但应注意同样的此处两次使用SC表,因此对他进行重命名以示区分】
注意嵌套查询中,一定要先从内层查询开始分析,进而分析外层查询。
三、集合查询
SELECT语句的查询结果是元组的集合,因此,可以利用有关集合的操作方法进行对于查询结果进行相关操作。有关集合的操作包含并操作(UNION)、交操作(INTERSECT)以及差操作(EXCEPT)。
SELECT *
FROM Student
WHERE Sdept = 'CS'
UNION
SELECT *
FROM Student
WHERE Sage <= 19
上述代码为将‘CS’专业的学生集合与年龄不大于19岁的学生集合取并集。
此处,额外强调:
- UNION:将多个查询结果合并起来时,系统自动去掉重复元组。
- UNION ALL:将多个查询结果合并起来时,保留重复元组。
SELECT Sno
FROM SC
WHERE Cno = '1' AND
Sno IN (SELECT Sno
FROM SC
WHERE Cno = '2')
上述代码为选择课程1与选择课程2的学生的交集。
SELECT *
FROM Student
WHERE Sdept = 'CS'
EXCEPT
SELECT *
FROM Student
WHERE Sage <= 19
上述代码为将‘CS’专业的学生集合与年龄不大于19岁的学生集合的差集【即选择那些‘CS’系中年龄大于19岁的学生】。
下面来看一个较为综合性的题目,统计学生姓名中每一个字出现的总次数
--统计姓名中每个汉字出现的次数
SELECT Text, COUNT(*)
FROM (SELECT Substring(Sname,1,1) AS Text FROM Student WHERE LEN(Sname)>=1
UNION ALL
SELECT Substring(Sname,2,1) FROM Student WHERE LEN(Sname)>=2
UNION ALL
SELECT Substring(Sname,3,1) FROM Student WHERE LEN(Sname)>=3
) AS T
GROUP BY Text
该代码较为综合,下面对其关键语句进行读取:
①COUNT:聚合计数函数,用于统计每一个字出现的次数
②Subtring:字符串截取函数,用于断开每一个字(从哪一位开始截取,截取长度为多少)
③LEN:字符串长度函数,用于判断姓名长度
④UNION ALL:集合的并,同时不消除重复项
上述代码的综合思想为:先将每一个人的姓名进行断开,每一个字单独充当一个元素,然后将这三个集合取并集,并将由这个并集构成的表命名为T,其中具有一个属性,为Text,然后根据该属性进行分组并计数即可。
四、小结
基于此,有关数据查询的相关代码已经全部讲解完毕,有关数据查询的基本代码框架如下:
灵活运用这些基本语句,就可以实现大部分的数据查询操作。