SQL基础复习04--数据查询SQL语句(多表查询)

参考教材《数据库系统:原理、设计与编程(MOOC版)》,陆鑫 张凤荔 陈安龙

3.4 数据查询SQL语句

SELECT [ALL/DISTINCT] <目标列>[,<目标列>...]
[INTO <新表>]
FROM <表名>[,<表名>...]
[WHERE <条件表达式>]
[GROUP BY <列名> [HAVING <条件表达式>]
    ORDER BY <列名> [ASC/DESC]];

SELECT语句由多种字句组成:

  1. SELECT子句,用来指明从数据库表中需要查询的目标列。ALL是默认操作,获取所有满足条件的数据行;DISTINCT用来去掉结果集中的重复数据行;<目标列>为被查询表的指定列名,可以有多个。
  2. INTO子句,用来将被查询的结果集数据插入新表。
  3. FROM子句,用来指定被查询的数据来自哪个表或哪些表。多表用逗号分隔。
  4. WHERE子句,用来给出查询的检索条件,多个条件之间可以用AND、OR进行连接。
  5. GROUP BY子句,用来对查询结果进行分组,并进行分组统计等处理,在分组中,还可以使用HAVING关键词定义分组条件。
  6. ORDER BY子句,用来对查询结果集进行排序。ASC当然是升序,DESC是降序。默认为ASC。

从SELECT语句的操作结果看,<目标列>实现对关系表的投影操作,WHERE <条件表达式>实现对关系表的元组选择操作。

3.4.9 使用子查询处理多表

可以在SELECT查询语句中使用子查询方式实现多表关联查询。

参考书中并未给出创建表格的语句,也未给出数据库文件,但却直接执行了多表查询。我根据一些查询的结果模糊的推断出了表的结构,并且创建了表。代码放在文章最后的附录中。

例3-36
关联教师表和学院表,检索出“计算机学院”的教师名单,采用子查询方法:

SELECT TeacherID, TeacherName, TeacherTitle
FROM Teacher
WHERE CollegeID IN
    (SELECT CollegeID
    FROM College
    WHERE CollegeName='计算机学院')
ORDER BY TeacherID;
GO

1.png

以上语句在处理多表查询时,仅仅在SELECT语句的WHERE子句中嵌套了一层SELECT子查询语句。子查询还可以嵌套多层SELECT子查询语句。但实际应用中,受限于DBMS处理SQL语句的性能,不宜嵌套过多子查询。
子查询只有在最终输出的信息完全来自一个表的情况下才有用,如果输出的信息来字多个表,应当使用连接查询。

3.4.10 使用连接查询多表

连接查询的基本思想是将关联表的主键值于外键值进行匹配对比,从中检索出符合条件的关联表信息。

例3-36-2
同例3-36,但采用连接查询方式处理:

SELECT TeacherID, TeacherName, TeacherTitle
FROM Teacher, College
WHERE Teacher.CollegeID=College.CollegeID AND College.CollegeName='计算机学院'
ORDER BY TeacherID;
GO

连接查询还有一个优势,就是输出的结果可以来字多个表,而不是跟子查询一样只能来字一个表。

例3-37
查询各个学院教师的人数信息。该操作需要关联教师信息表和学员信息表,查询学院名称、教师人数,输出按名称降序排列:

SELECT College.CollegeName AS 学院名称, COUNT(Teacher.TeacherID) AS 教师人数
FROM Teacher, College
WHERE Teacher.CollegeID=College.CollegeID
GROUP BY College.CollegeName
ORDER BY College.CollegeName DESC;
GO

2.png

由上面代码可以发现,GROUP BYORDER BY的参数只能是SELECT后面跟着的参数,也就是只能是查询结果中的列。这里想一下也是可以想通的。同时分组列名和排序列名需要一致。

为了在多表连接查询中简化列名的表名限定,可以(在FROM子句中)使用AS关键词给表名赋予一个简单名称。
例3-38
查询各个学院的教师的信息。关联Teacher表和College表,查询CollegeName、TeacherID、TeacherName、TeacherGender、TeacherTitle。按学院名称、编号分别排序输出:

SELECT B.CollegeName AS 学院名称, A.TeacherID AS 编号, A.TeacherName AS 姓名, A.TeacherGender AS 性别, A.TeacherTitle AS 职称
FROM Teacher AS A, College AS B
WHERE A.CollegeID=B.CollegeID
ORDER BY B.CollegeName, A.TeacherID;
GO

3.png

3.4.11 SQL JOIN...ON连接

实现多表关联查询还可以用JOIN...ON关键字的格式。两表关联查询的JOIN...ON连接语句格式:

SELECT <目标列>[,<目标列>...]
FROM <表名1> JOIN <表名2> ON <连接条件>;

例3-39
使用JOIN...ON实现例3-38:

SELECT B.CollegeName AS 学院名称, A.TeacherID AS 编号, A.TeacherName AS 姓名, A.TeacherGender AS 性别, A.TeacherTitle AS 职称
FROM Teacher AS A JOIN College AS B
ON A.CollegeID=B.CollegeID
ORDER BY B.CollegeName, A.TeacherID;
GO

结果与例3-38是相同的。
使用JOIN...ON关联查询语句,还可以实现两个以上的表关联查询。其中3表关联查询的JOIN...ON连接语句格式如下:

SELECT <目标列>[,<目标列>...]
FROM <表名1> JOIN <表名2> ON <连接条件1> JOIN <表名3> ON <连接条件2>;

但我在一些博客和微信公众号文章中曾经看到过有朋友测试发现,MySQL使用JOIN进行3表及3表以上的连接时,会有一些问题,但Oracle数据库就可以。这里需要引起注意。(我自己测试的时候,mysql 8点几的版本,4表连接也是没有问题的,可能出问题的是老版本。)

此处的例题用到的多个数据库中的数据,根据书上的内容难以推断。希望以后出书的人可以把这些省略去但又非常重要的东西加上,不要省掉。因为缺少数据,此处的例题不再做了,只把书上的例题代码敲上,方便查阅。

例3-40
查询课表信息,关联Teacher、Course、Plan、College四个表,查询课程名称、教师姓名、上课地点、上课时间、开课学院等信息,按开课计划编号排序输出:

SELECT C.CourseName AS 课程名称, T.TeacherName AS 教师姓名, P.CourseRoom AS 地点, P.CourseTime AS 时间, S.CollegeName AS 开课学院
FROM Course AS C JOIN Plan AS P ON C.CourseID=P.CourseID JOIN Teacher AS T ON P.TeacherID=T.TeacherID
JOIN College AS S ON S.CollegeID=T.CollegeID
ORDER BY P.CoursePlanID;
GO

上面的连接查询使用Course的主键与Plan的外键进行匹配关联,同时也使用Teacher的主键与Plan的外键进行匹配关联,还使用College的主键与Teacher的外键进行匹配关联,这样实现了4表关联数据查询。

  1. 内连接
    以上的JOIN...ON连接查询中,只有关联表相关字段的列值满足等值连接条件时,才从这些关联表中提取数据组合成新的结果集,这样的连接被称为JOIN...ON内连接。

    例3-41
    查询所有课程的学生选课情况,包括开设课程名称、选课学生人数。需要关联Course、Plan、Register。使用内连接查询:

    SELECT C.CourseName AS 课程名称, T.TeacherName AS 教师, COUNT(R.CoursePlanID) AS 选课人数
    FROM Course AS C JOIN Plan AS P
    ON C.CourseID=P.CourseID
    JOIN Teacher AS T ON P.TeacherID=T.TeacherID
    JOIN Register AS R ON P.CoursePlanID=R.CoursePlanID
    GROUP BY C.CourseName, T.TeacherName;
    GO
    

    上面的内连接查询中,只能找出有学生注册的课程名称和选课人数,不能找出没有学生注册的课程信息。

  2. 外连接
    有时候我们也希望输出那些不满足连接条件的元组数据。可以使用JOIN...ON外连接方式实现。有3中形式:

    • LEFT JOIN: 左外连接,即使右表中没有匹配,也从左表返回所有的行。
    • RIGHT JOIN: 右外连接,即使左表中没有匹配,也从右表返回所有的行。
    • FULL JOIN: 全外连接,只要其中一个表中存在匹配,就返回行。

    例3-42
    查询所有开设课程的学生选课情况,包括开设课程名称、选课学生人数。需要关联Course、Plan、Register。希望不但能找出有学生注册的课程信息,也能找出没有学生注册的课程信息。使用左外连接查询:

    SELECT C.CourseName AS 课程名称, T.TeacherName AS 教师, COUNT(R.CoursePlanID) AS 选课人数
    FROM Course AS C JOIN Plan AS P
    ON C.CourseID=P.CourseID
    JOIN Teacher AS T ON P.TeacherID=T.TeacherID
    LEFT JOIN Register AS R ON P.CoursePlanID=R.CoursePlanID
    GROUP BY C.CourseName, T.TeacherName;
    GO
    

无法自己实现例题,对概念的理解大打折扣,但没有办法。因为缺少数据,以后的几章可能都无法实现例题。所以我计划在学完所有SQL语句之后,自己搞一个数据库的项目,把学过去的所有知识实现一遍,以深入理解各类SQL语句的功能与使用。

附录代码:

CREATE TABLE College
    (CollegeID int IDENTITY(1,1) PRIMARY KEY,
    CollegeName varchar(40) NOT NULL);
GO

INSERT INTO College VALUES('软件学院');
INSERT INTO College VALUES('计算机学院');
SELECT * FROM College;
GO

CREATE TABLE Teacher
    (TeacherID char(4) NOT NULL,
    TeacherName varchar(10) NOT NULL,
    TeacherTitle varchar(6),
    TeacherGender char(2) CHECK(TeacherGender IN('男', '女')),
    CollegeID int NOT NULL,
    CONSTRAINT Teacher_PK PRIMARY KEY(TeacherID),
    CONSTRAINT CollegeID_FK FOREIGN KEY(CollegeID) REFERENCES College(CollegeID) ON DELETE CASCADE);
GO

ALTER TABLE Teacher
ADD CONSTRAINT CK_Teacher_Teacher_04E4BC85 CHECK(TeacherTitle IN('教授', '副教授', '讲师'));

INSERT INTO Teacher VALUES('T000', '张键', '副教授', '男', 2);

UPDATE Teacher
SET TeacherID='T001'
WHERE TeacherName='张键';
GO

SELECT * FROM Teacher;
GO

INSERT INTO Teacher VALUES('T002', '万佐', '教授', '男', 2);
INSERT INTO Teacher VALUES('T003', '青迎', '副教授', '女', 2);
INSERT INTO Teacher VALUES('T004', '马敬', '教授', '男', 2);
INSERT INTO Teacher VALUES('T005', '赵微', '讲师', '女', 2);
INSERT INTO Teacher VALUES('T006', '汪明', '副教授', '男', 1);
INSERT INTO Teacher VALUES('T007', '傅超', '副教授', '男', 1);
INSERT INTO Teacher VALUES('T008', '李力', '教授', '男', 1);
INSERT INTO Teacher VALUES('T009', '杨阳', '副教授', '女', 1);
INSERT INTO Teacher VALUES('T010', '楚青', '副教授', '女', 1);
GO
posted @ 2020-05-25 13:09  Kit_L  阅读(438)  评论(0编辑  收藏  举报