zoukankan      html  css  js  c++  java
  • 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
    
  • 相关阅读:
    MySQL数据库学习笔记(八)----JDBC入门及简单增删改数据库的操作
    vim使用技巧大全
    virtualbox下centos虚拟机安装增强工具教程和常见错误解决
    python初始化list列表(1维、2维)
    Python中列表(list)、字典(dict)排序的程序
    字符画
    php 过滤器filter_var验证邮箱/url/ip等
    Python3 MySQL 数据库连接
    PHP socket 服务器框架集
    python3 获取int最大值
  • 原文地址:https://www.cnblogs.com/Kit-L/p/12956330.html
Copyright © 2011-2022 走看看