八,查询处理

示例数据库

CREATE DATABASE Study
GO
USE Study
CREATE TABLE student (
    s_id char(6) NOT NULL,
    name varchar(10) NOT NULL,
    dept varchar(15) NULL,
    gpa float NULL,
    CONSTRAINT pk_student PRIMARY KEY (s_id)
)
GO
INSERT INTO student VALUES('201701', '张三', '计科院', 3.4)
INSERT INTO student VALUES('201702', '李四', '化工院', 1.8)
INSERT INTO student VALUES('201703', 'Sam', '体育学院', 2.6)
INSERT INTO student VALUES('201704', '王五', '化工院', 3.8)
INSERT INTO student VALUES('201705', '李华', '外语院', 2.9)
INSERT INTO student VALUES('201706', 'Anny', '计科院', 3.4)
INSERT INTO student VALUES('201707', '小明', '体育学院', 2.1)
INSERT INTO student VALUES('201708', '王麻子', '计科院', 4.0)
GO
CREATE TABLE course (
    c_id char(4) NOT NULL,
    name varchar(15) NOT NULL,
    credit int,
    CONSTRAINT pk_course PRIMARY KEY (c_id)
)
GO
INSERT INTO course VALUES('1001', '高等数学', 4)
INSERT INTO course VALUES('1002', '体育基础', 2)
INSERT INTO course VALUES('1003', '大学英语', 3)
INSERT INTO course VALUES('1004', '程序设计基础', 4)
INSERT INTO course VALUES('1005', '中国近代史', 2)
INSERT INTO course VALUES('2001', '数据库基础', 3)
INSERT INTO course VALUES('3001', '有机化学', 4)
INSERT INTO course VALUES('3002', '无机化学', 4)
INSERT INTO course VALUES('4001', '运动康复', 4)
INSERT INTO course VALUES('5005', '俄语', 2)
INSERT INTO course VALUES('7003', '形体与姿态', 2)

GO
CREATE TABLE ch_course (
    s_id char(6) NOT NULL,
    c_id char(4) NOT NULL,
    CONSTRAINT fk_ch_course_s_id FOREIGN KEY(s_id) REFERENCES student(s_id),
    CONSTRAINT fk_ch_course_c_id FOREIGN KEY(c_id) REFERENCES course(c_id)
)
GO
INSERT INTO ch_course VALUES('201701', '1001')
INSERT INTO ch_course VALUES('201701', '1003')
INSERT INTO ch_course VALUES('201701', '1004')
INSERT INTO ch_course VALUES('201701', '2001')

INSERT INTO ch_course VALUES('201706', '1001')
INSERT INTO ch_course VALUES('201706', '1003')
INSERT INTO ch_course VALUES('201706', '1004')
INSERT INTO ch_course VALUES('201706', '2001')

INSERT INTO ch_course VALUES('201708', '1001')
INSERT INTO ch_course VALUES('201708', '1002')
INSERT INTO ch_course VALUES('201708', '1003')
INSERT INTO ch_course VALUES('201708', '1004')
INSERT INTO ch_course VALUES('201708', '1005')
INSERT INTO ch_course VALUES('201708', '2001')

INSERT INTO ch_course VALUES('201702', '1001')
INSERT INTO ch_course VALUES('201702', '1003')
INSERT INTO ch_course VALUES('201702', '1004')
INSERT INTO ch_course VALUES('201702', '3001')
INSERT INTO ch_course VALUES('201702', '3002')

INSERT INTO ch_course VALUES('201704', '1001')
INSERT INTO ch_course VALUES('201704', '1002')
INSERT INTO ch_course VALUES('201704', '1003')
INSERT INTO ch_course VALUES('201704', '3001')
INSERT INTO ch_course VALUES('201704', '3002')

INSERT INTO ch_course VALUES('201703', '1002')
INSERT INTO ch_course VALUES('201703', '1003')
INSERT INTO ch_course VALUES('201703', '4001')

INSERT INTO ch_course VALUES('201707', '1002')
INSERT INTO ch_course VALUES('201707', '1003')
INSERT INTO ch_course VALUES('201707', '4001')
INSERT INTO ch_course VALUES('201707', '7003')

INSERT INTO ch_course VALUES('201705', '1002')
INSERT INTO ch_course VALUES('201705', '1003')
INSERT INTO ch_course VALUES('201705', '5005')
示例数据库

 

查询数据

  SQL语言提供了SELECT语句进行数据查询,一般格式如下:

    SELECT [DISTINCT] <目标列表达式> [,...n]

    FROM <表名或视图名> [,...n]

    [WHERE <条件表达式>]

    [GROUP BY <列名1> [HAVING <条件表达式>] ]

    [ORDER BY <列名2> [ASC | DESC] ]

  语句含义:根据WHERE子句的条件表达式,从FROM子句指定的表或视图,找出满足条件的元组,再按SELECT子句中的目标列表达式,选出元组中的属性值形成结果表。如果有GROUP子句,则将结果按<列名1>的值进行分组,该属性列值相等的元组分为一组,每个产生结果表中的一条记录。通常会在每组中作用集函数。如果GROUP子句带HAVING短语,则只输出满足HAVING条件的组。如果有ORDER子句,则还要按照<列名2>值的升序或降序对结果表进行排序。

简单查询

  简单查询指仅涉及一张表的查询。

  最简单的查询

  将SELECT语句的大部分成分省略后就得到最简单的查询命令

    SELECT [DISTINCT] <目标列表达式> [,...n] FROM <表名或视图名>

  1. 查询指定列
  2. 查询所有列  SELECT使用  * 表示表的所有列
  3. 查询计算列  <目标列表达式>可以是由常量,变量和函数构成的表达式
  4. 列别名  (1)使用AS关键字:<目标列表达式> [AS] <别名> (2)SQL Server支持的“=”连接:<别名> = <目标列表达式>
  5. 使用DISTINCT关键字消除重复元组

  查询满足条件的元组

  通过再WHERE子句指定查询条件实现。SQL Server中,查询条件是一个返回TRUE,FALSE或UNKNOWN(由值为NULL的数据参与逻辑运算所返回的结果)三种逻辑值的逻辑表达式。

  

 

 

   WHERE子句常用查询条件

  

 

 

   通配符转义:

    模式字符串中的通配符(%,_,[,])已被赋予特殊含义,要恢复其原意,就要使用ESCAPE短语对通配符进行转义。

    eg:查询以“DB_”开通的课程信息

      SELECT * FROM 课程表 WHERE 课名 LIKE 'DB\_%' ESCAPE '\'

    ESCAPE '\'短语表示“\”是换码字符,这样模式字符串紧跟再“\”后面的字符“_”不再具有通配符含义,而被转义为普通的“_”字符。但是“%”仍然是通配符。

  逻辑运算符优先级:NOT > AND > OR  括号可改变运算优先级。

 

统计

  常用统计函数:(DISTINCT关键字可选,表示统计时去除重复值)

  • COUNT([DISTINCT] *)        统计元组个数
  • COUNT([DISTINCT] <列表达式>)        统计列值个数
  • SUM([DISTINCT] <列表达式>)        计算数值型列表达式的总和
  • AVG([DISTINCT] <列表达式>)        计算数值型列表达式的平均值
  • MAX([DISTINCT] <列表达式>)        求列表达式的最大值
  • MIN([DISTINCT] <列表达式>)        求列表达式的最小值

分组查询

  GROUP BY子句可以将查询结果按一列或多列取值相等的原则进行分组。含GROUP BY子句的查询称为分组查询。

  eg:统计每门课的选课人数  

SELECT c_id, COUNT(s_id)
FROM ch_course
GROUP BY c_id

  

 

 

   注意:

  • GROUP BY子句中的列名只能是FROM子句所列表的列名,不能是列的别名。
  • 使用GROUP BY子句后,SELECT子句的目标列表达式所涉及的列必须满足:要么在GROUP BY子句中,要么再某个统计函数中。

  使用HAVING短语来筛选组

  eg:统计选课人数大于3的课程

SELECT c_id, COUNT(s_id)
FROM ch_course
GROUP BY c_id
HAVING COUNT(s_id) > 3

  

 

 

   WHERE子句与HAVING短语的区别:

  • 作用对象不同。WHERE子句作用于FROM子句所列的表;HAVING短语作用于组。
  • 选择条件的构成有差异。WHERE条件不能直接包含统计函数;HAVING条件所涉及的列必须要么在GROUP BY子句中,要么在某个统计函数中。

 

连接查询

  连接查询与单表查询的主要区别在于涉及表的数量不同。如果将FROM子句中的多个表看成由这些表的笛卡尔积构成的一张大表,那么连接查询实际上就是再这张大表上的单表查询。

  连接查询的特殊性:

  • 由于不同表的某些列可能重名,语句中设计的重名列,需要在列名前加“<表名>.”进行限定。
  • 在连接查询中,如果没有WHERE子句,查询结果将是没有实际意义的笛卡尔积。WHERE条件应包括必须的连接条件和可选的普通查询条件。
  • 在涉及n张表的连接查询中,至少应包括n-1个连接条件,否则,这n张表之间的某些位置将蜕化为没有实际意义的笛卡尔积。

  eg:查询学生信息及其所选课程

SELECT student.*, course.name, credit
FROM student, course, ch_course
WHERE student.s_id = ch_course.s_id 
    AND course.c_id = ch_course.c_id

  

 

 

 

 

  FROM子句后的表可设置别名

  eg:

SELECT X.*, Y.name, credit
FROM student AS X, course AS Y, ch_course Z
WHERE X.s_id = Z.s_id 
    AND Y.c_id = Z.c_id

  使用JOIN和ON关键字

  可以用JOIN和ON关键字将连接条件和普通查询条件分开。普通查询条件仍写在WHERE子句中。JOIN用于连接两张表,ON则用于给出连接条件。

    SELECT 子句

    FROM <表名> {JOIN <表名> ON <连接条件>} [ ...n ]

    [WHERE <普通查询条件>]

    [其它子句]

  eg:查询课程号为'1001'的课程的选课学生信息

SELECT X.*, Y.name, credit
FROM ch_course Z JOIN student X ON X.s_id = Z.s_id
    JOIN course Y ON Z.c_id = Y.c_id
WHERE y.c_id = '1001'

 

  

 

 

外连接

  通常的连接查询值输出满足连接条件的元组。有时需要以一张表为主体输出,对于连接表中没有的元组以空值填充,这就需要使用外连接。

  外连接分为左外连接,右外连接和全外连接。相应的可将普通连接称为内连接。

  • 左外连接是指在连接时要将左边关系中的未用元组配上空值加到结果集中。可以通过将连接条件中的“ = ”改成“ *= ”,或者将JOIN关键字改成LEFT OUTER JOIN来表示左外连接。
  • 右外连接是指在连接时要将右边关系中的未用元组配上空值加到结果集中。可以通过将连接条件中的“ = ”改成“ =* ”,或者将JOIN关键字改成RIGHT OUTER JOIN来表示左外连接。
  • 全外连接是指在连接时要将左边关系和右边关系中的未用元组都配上空值加到结果集中。可以通过将JOIN关键字改成FULl OUTER JOIN来表示全外连接。

子查询

  在SQL语言中,一条SELECT语句称为一个查询块。将一个查询块用圆括号括起,就表示由这个查询块返回的元组构成的集合。可以通过将这个集合放在另一个查询块的WHERE子句或HAVING短语中进行各种集合检查,来表达查询条件。这种查询称为嵌套查询,其中上层查询块称为父查询,下层查询块称为子查询。

  对查询结果集的检查包括:

  • 检查给定值是否在结果集中
  • 用给定值和结果集中的元素进行大小比较
  • 检查结果集是否为空

  检查给定值是否在结果集中

eg:查询选修了“大学英语”的学生学号和姓名

SELECT s_id, name
FROM student
WHERE s_id IN (SELECT s_id
    FROM ch_course
    WHERE c_id IN (SELECT c_id
        FROM course
        WHERE name='大学英语'
    )
)

  

 

   嵌套查询的特点:

  • 求解顺序由内向外。子查询的结果用于建立父查询的查询条件。
  • 可用一系列简单查询构成复杂查询,增强了SQL的查询能力。子查询的嵌套层数没有限制。
  • 如果父查询与子查询用IN或比较运算符连接,则子查询的SELECT子句只能由一个列表达式。
  • 如果父查询与子查询用IN或比较运算符连接,则IN或比较运算符左边的列表达式和右边SELECT子句中的列表达式应具有相同的含义,否则得不到正确结果。

  

  用给定值与结果集中的元素比较大小

  单值比较:

  用户能确切知道子查询的结果集只包含一个值时,可以用比较运算符直接连接父查询的列表达式和子查询结果集,实现大小的比较。

  在SQL Server中,返回单值的子查询可以作为一个值参加任何合法的表达式运算。

  eg:查询学费绩点比sam高的学生的学号姓名

SELECT s_id, name 
FROM student
WHERE gpa > (SELECT gpa 
    FROM student
    WHERE name='sam')

  

 

   多值比较:

  指当子查询的结果集包含多个值时,用给定值和结果集中的某个值进行比较。此时父查询与子查询之间要用比较运算符后缀ANybody或ALL进行连接。

  

 

   eg:查询gpa比计科院所有学生都低的学生名单

SELECT s_id, name, gpa 
FROM student
WHERE gpa <ALL (SELECT gpa 
    FROM student
    WHERE dept='计科院')

  

 

   使用统计函数

SELECT s_id, name, gpa 
FROM student
WHERE gpa < (SELECT MIN(gpa) 
    FROM student
    WHERE dept='计科院')

  事实上,使用统计函数实现子查询通常比直接使用ANY或ALL实现查询效率要高。

  

 

 

  检查结果集是否为空

  可以用关键字EXISTS来检查子查询的结果集是否为空,检查结果时逻辑值“真”或“假”。如果NOT EXISTS检查返回“真”,则子查询结果集为空。

  • 子查询往往要引用父查询所涉及的表。父查询不允许引用子查询涉及的表。
  • 子查询的SELECT子句一般写成SELECT *即可,无须给出具体列名

 

联合查询

  每一个SELECT语句都能获得一个或一组元组。使用UNION操作把多个SELECT语句的结果合并。

  使用UNION将多个查询结果合并时,系统会自动去掉重复元组。

  参加UNION操作的各结果表的列数必须相同,对应列的数据类型也必须相同,结果表的列名取第一个SELECT语句定义的列名

posted @ 2020-06-07 17:42  爱十三的柒  阅读(310)  评论(0编辑  收藏  举报