第 6章 查询技术
SELECT 主要子句
SELECT [ ALL | DISTINCT ]
[TOP expression [PERCENT] [WITH TIES ]]
< select_list >
[ INTO new_table ]
[ FROM { <table_source> } [,...n ] ]
[ WHERE <search_condition> ]
[ GROUP BY [ ALL ] group_by_expression [,...n ]
[ WITH { CUBE | ROLLUP } ]
[ HAVING < search_condition > ]
[ORDER BY order_expression [ASC|DESC]]
[ COMPUTE {{AVG|COUNT|MAX|MIN|SUM}
(expression)} [,...n ]
[ BY expression [,...n ] ]
SELECT 主要子句参数说明如下:
SELECT子句用于指定所选择的要查询的特定表中的列,它可以是星号( *)、表达式、列表、变量等。
INTO子句用于指定所要生成的新表的名称。
FROM子句用于指定要查询的表或者视图,最多可以指定 16个表或者视图,用逗号相互隔开。
WHERE子句用来限定查询的范围和条件。
GROUP BY子句是分组查询子句。
HAVING子句用于指定分组子句的条件。
GROUP BY子句,HAVING子句和集合函数一起可以实现对每个组生成一行和一个汇总值。
ORDER BY子句可以根据一个列或者多个列来排序查询结果,在该子句中,既可以使用列名,也可以使用相对列号。
ASC表示升序排列,DESC表示降序排列。
COMPUTE子句使用集合函数在查询的结果集中生成汇总行。
COMPUTE BY子句用于增加各列汇总行。
6.1 基本 SELECT语句
6.1.1 投影查询
6.1.2 条件查询
6.1.1 投影查询
最基本的 SELECT 语句仅有两个部分:要返回的列,
和这些列源于的表。也就是说查询均为不使用 WHERE
子句的无条件查询,也称作投影查询。
例 6-1 查询全体学生的学号、姓名和年龄。
程序清单如下:
SELECT SNO,SN,AGE FROM S
例 6-2 查询学生的全部信息。
程序清单如下:
SELECT * FROM S
注意:用‘ * ’表示表的全部列名,而不必逐一列出。
6.1.1 投影查询
例 6-3 查询选修了课程的学生号。
程序清单如下:
SELECT DISTINCT SNO FROM SC
注意:应用 DISTINCT消除查询结果以某列为依据的重复行。上例中,
sc表中相同学号( SNO)的纪录只保留第一行,余下的具有相同学号的记录将从查询结果中清除。也就是每个同学保留一条选课纪录。
另外,利用投影查询可控制列名的顺序,并可通过指定别名改变查询结果的列标题的名字,如下例。
例 6-4 查询全体学生的姓名、学号和年龄。
程序清单如下:
SELECT SN NAME,SNO,AGE FROM S
注意,NAME为 SN的别名,这里我们改变了列的显示顺序。
6.1.2 条件查询
当要在表中找出满足某些条件的行时,则需使用
WHERE子句指定查询条件。 WHERE子句中,条件通常通过三部分来描述:列名;比较运算符;列名、常数。
条件查询又可分为以下几方面内容:
1、比较大小和确定范围;
2、部分匹配查询;
3、空值查询;
4、查询的排序
6.1.2 条件查询
1、比较大小和确定范围
例 6-5 查询选修课程号为‘ C1?的学生的学号和成绩。
程序清单如下:
SELECT SNO,SCORE FROM SC WHERE CNO=?C1?
例 6-6 查询成绩高于 85分的学生的学号、课程号和成绩。
程序清单如下:
SELECT SNO,CNO,SCORE FROM SC WHERE
SCORE>85
6.1.2 条件查询
1、比较大小和确定范围
当 WHERE子句需要指定一个以上的查询条件时,则需要使用逻辑运算符 AND,OR
和 NOT将其连结成复合的逻辑表达式。其优先级由高到低为,NOT,AND,OR,用户可以使用括号改变优先级。
例 6-7 查询选修 C1或 C2且分数大于等于 85分学生的的学号、课程号和成绩。
程序清单如下:
SELECT SNO,CNO,SCORE FROM SC
WHERE( CNO=?C1? OR CNO=?C2?) AND SCORE>=85
SQL语句中也有一个特殊的 BETWEEN 运算符,用于检查某个值是否在两个值之间
(包括等于两端的值)。
例 6-8 查询工资在 1000至 1500之间的教师的教师号、姓名及职称。
程序清单如下:
SELECT TNO,TN,PROF FROM T
WHERE SAL BETWEEN 1000 AND 1500
上面 SQL语句等价于以下语句:
SELECT TNO,TN,PROF FROM T
WHERE SAL>=1000 AND SAL<=1500
6.1.2 条件查询
1、比较大小和确定范围
注意:在 SELECT语句中可利用,IN”操作来查询属性值属于指定集合的元组。
利用,NOT IN”可以查询指定集合外的元组。如下面两个例子。
例 6-10 查询选修 C1或 C2的学生的学号、课程号和成绩。
程序清单如下:
SELECT SNO,CNO,SCORE
FROM SC
WHERE CNO IN(?C1?,?C2?)
此语句也可以使用逻辑运算符,OR”实现。相应的程序清单如下:
SELECT SNO,CNO,SCORE
FROM SC
WHERE CNO=?C1? OR CNO=?C2?
6.1.2 条件查询
2、部分匹配查询
当不知道完全精确的値时,用户还可以使用 LIKE或 NOT LIKE
进行部分匹配查询(也称模糊查询)。 LIKE运算使我们可以使用通配符来执行基本的模式匹配。
使用 LIKE运算符的一般格式为:
<属性名 > LIKE <字符串常量 >
字符串常量的字符可以包含如表 6-2所示的通配符。
通配符 说明
_ 表示任意单个字符
% 表示任意长度的字符串
[ ] 与特定范围(例如,[a-f])
或特定集(例如,
[abcdef])中的任意单字符匹配。
[^] 与特定范围(例如,[^a-f])
或特定集(例如,
[^abcdef])之外的任意单字符匹配。
表 6-2 通配符及说明
6.1.2 条件查询
2、部分匹配查询
例 6-12 查询所有姓张的教师的教师号和姓名。
程序清单如下:
SELECT TNO,TN
FROM T
WHERE TN LIKE?张 %?
例 6-13 查询姓名中第二个汉字是“力”的教师号和姓名。
程序清单如下:
SELECT TNO,TN
FROM T
WHERE TN LIKE?_力 %?
6.1.2 条件查询
3、空值查询
某个字段没有值称之为具有空值( NULL)。通常没有为一个列输入值时,该列的值就是空值。空值不同于零和空格,它不占任何存储空间。例如,某些学生选课后没有参加考试,有选课记录,但没有考试成绩,考试成绩为空值,这与参加考试,成绩为零分的不同。
例 6-15 查询没有考试成绩的学生的学号和相应的课程号。
程序清单如下:
SELECT SNO,CNO
FROM SC
WHERE SCORE IS NULL
注意:这里的空值条件为 IS NULL,不能写成 SCORE=NULL。
6.1.2 条件查询
4.查询的排序
当需要对查询结果排序时,应该在 SELECT语句中使用 ORDER BY子句。
ORDER BY 子句包括了一个或多个用于指定排序顺序的列名,排序方式可以指定,
DESC为降序,ASC为升序,缺省时为升序。 ORDER BY子句必须出现在其他子句之后。
ORDER BY 子句支持使用多列。可以使用以逗号分隔的多个列作为排序依据:查询结果将先按指定的第一列进行排序,然后再按指定的下一列进行排序。
例 6-16 查询选修 C1 的学生学号和成绩,并按成绩降序排列。
程序清单如下:
SELECT SNO,SCORE
FROM SC
WHERE CNO='C1'
ORDER BY SCORE DESC
6.2 分组查询
6.2.1 聚合函数和 GROUP BY子句
6.2.2 GROUP BY 和 WHERE 子句,HAVING
子句
6.2.1 聚合函数和 GROUP BY子句
GROUP BY子句可以将查询结果按属性列或属性列组合在行的方向上进行分组,每组在属性列或属性列组合上具有相同的聚合值。如果聚合函数没有使用 GROUP BY 子句,则只为 SELECT
语句报告一个聚合值。常用的聚合函数,如表 6-3所示。
函数名称 MIN MAX SUM AVG COUNT COUNT(*)
功能 求一列中的最小值求一列中的最大值按列计算值的总和按列计算平均值按列值计个数返回表中的所用行数表 6-3常用的聚合函数
6.2.1 聚合函数和 GROUP BY子句
例 6-18 通过查询求学号为 S1学生的总分和平均分。
程序清单如下:
SELECT SUM(SCORE) AS TotalScore,AVG(SCORE) AS AveScore
FROM SC
WHERE SNO = 'S1'
注意:函数 SUM和 AVG只能对数值型字段进行计算。
例 6-19 通过查询求选修 C1号课程的最高分、最低分及之间相差的分数程序清单如下:
SELECT MAX(SCORE) AS MaxScore,MIN(SCORE) AS MinScore,
MAX(SCORE)- MIN(SCORE) AS Diff
FROM SC
WHERE (CNO = 'C1')
6.2.1 聚合函数和 GROUP BY子句
例 6-20 通过查询求管理系学生的总数。
程序清单如下:
SELECT COUNT(SNO) FROM S
WHERE DEPT='管理 '
例 6-21 通过查询求学校中共有多少个系。
程序清单如下:
SELECT COUNT(DISTINCT DEPT) AS DeptNum
FROM S
注意:加入关键字 DISTINCT后表示消去重复行,可计算字段,DEPT“不同值的数目。
COUNT函数对空值不计算,但对零进行计算。
例 6-22 统计有成绩的学生的人数。
程序清单如下:
SELECT COUNT (SCORE)
FROM SC
注意:上例中成绩为零的同学计算在内,没有成绩(即为空值)的不计算 。
6.2.1 聚合函数和 GROUP BY子句
例 6-23 利用特殊函数 COUNT(*)求计算机系学生的总数程序清单如下:
SELECT COUNT(*) FROM S WHERE DEPT=?计算机’
注意:上例中,COUNT( *)用来统计元组的个数。此函数不消除重复行,也不允许使用 DISTINCT关键字。
在分组查询中,只要表达式中不包括聚合函数,就可以按该表达式分组。如下例所示。
例 6-24 查询每位学生的学号及其选课的门数。
程序清单如下:
SELECT CNO,COUNT(*) AS C_NUM FROM SC GROUP BY CNO
GROUP BY子句按 CNO的值分组,所有具有相同 CNO的元组为一组,对每一组使用函数 COUNT进行计算,统计出各位学生选课的门数。
例 6-25统计各年度出生的雇员人数程序清单如下。
Use adventureworks
SELECT DATEPART(year,birthdate ) AS Year,
COUNT(*) AS NumberOfemployees
FROM humanresources.employee
GROUP BY DATEPART(year,birthdate)
6.2.2 GROUP BY 和 WHERE 子句、
HAVING 子句
可以在包含 GROUP BY 子句的查询中使用 WHERE 子句。
在完成任何分组之前,将消除不符合 WHERE 子句中的条件的行。若在分组后还要按照一定的条件进行筛选,则需使用
HAVING子句。
例 6-26 在分组查询中使用 WHERE条件,查询计算机系的学生学号及平均成绩。
程序清单如下:
SELECT sno,AVG(score) AS 'AverageScore'
FROM sc
WHERE sno=(select sno from s where dept=?计算机’ )
GROUP BY sno
ORDER BY sno
GO
6.2.2 GROUP BY 和 WHERE 子句、
HAVING 子句
例 6-27 在分组查询中使用 HAVING条件,查询平均成绩大于 85的学生学号及平均成绩。
程序清单如下:
SELECT sno,AVG(score) AS 'AverageScore'
FROM sc
GROUP BY sno
HAVING AVG(score) >85
GO
注意:如果 HAVING 中包含多个条件,那么这些条件将通过 AND,OR 或 NOT 组合在一起
6.2.2 GROUP BY 和 WHERE 子句、
HAVING 子句
例 6-28 查询选课在三门以上且各门课程均及格的学生的学号及其总成绩,查询结果按总成绩降序列出。
程序清单如下:
SELECT SNO,SUM(SCORE) AS TotalScore
FROM SC
WHERE SCORE>=60
GROUP BY SNO
HAVING COUNT(*)>=3
ORDER BY SUM(SCORE) DESC
6.3 连接查询数据表之间的联系是通过表的字段值来体现的,这种字段称为连接字段。连接操作的目的就是通过加在连接字段的条件将多个表连接起来,以便从多个表中查询数据。前面的查询都是针对一个表进行的,当查询同时涉及两个以上的表时,称为连接查询。
6.3.1 等值连接与非等值连接
6.3.2自身连接
6.3.1 等值连接与非等值连接
连接条件的一般格式为:
[<表名 1>.] <列名 1> <比较运算符 > [<表名 2>.] <列名 2>
其中,比较运算符主要有:=、>、<、>=、<
=、!=。当比较运算符为“=”时,称为等值连接,其他情况为非等值连接。
例 6-29 查询张飞同学所选修的课程。
SELECT S.SNO,SN,CNO
FROM S,SC
WHERE (S.SNO = SC,SNO) AND (SN=?张飞’ )
6.3.1 等值连接与非等值连接
例 6-30 查询所有选课学生的学号、姓名、选课名称及成绩。
程序清单如下:
SELECT S.SNO,SN,CN,SCORE
FROM S,C,SC
WHERE S.SNO=SC.SNO
AND SC.CNO=C.CNO
注意:本例涉及三个表,WHERE子句中有两个连接条件。当有两个以上的表进行连接时,称为多表连接。
6.3.2 自身连接
当一个表与其自已进行连接操作时,称为表的自身连接。要查询的内容均在同一表中,可以将表分别取两个别名,一个是 X,
一个是 Y。将 X,Y中满足查询条件的行连接起来。这实际上是同一表的自身连接。
例 6-31 查询所有比李明工资高的教师姓名、性别、工资和刘伟的工资。
程序清单如下:
SELECT X.TN,X.SAL AS SAL_a,Y.SAL AS SAL_b
FROM T AS X,T AS Y
WHERE X.SAL>Y.SAL AND Y.TN='李明 '
6.3.2 自身连接例 6-32 检索所有学生姓名,年龄和选课名称。
程序清单如下:
SELECT SN,AGE,CN
FROM S,C,SC
WHERE S.SNO=SC.SNO AND
SC.CNO=C.CNO
6.4 子查询在 WHERE子句中包含一个形如 SELECT-FROM-
WHERE的查询块,此查询块称为子查询或嵌套查询,
包含子查询的语句称为父查询或外部查询。
6.4.1返回一个值的子查询
6.4.1返回一个值的子查询
6.4.1 返回一个值的子查询
当子查询的返回值只有一个时,可以使用比较运算符
( =,>,<,>=,<=,!=)将父查询和子查询连接起来。
例 6-33 查询与李明教师职称相同的教师号、姓名。
程序清单如下:
SELECT TNO,TN
FROM T
WHERE PROF=(SELECT PROF
FROM T
WHERE TN='李明 ')
6.4.2 返回一组值的子查询如果子查询的返回值不止一个,而是一个集合时,则不能直接使用比较运算符,可以在比较运算符和子查询之间插入 ANY或 ALL。
1,使用 ANY
2,使用 IN
3,使用 ALL
4,使用 EXISTS
6.4.2 返回一组值的子查询
1.使用 ANY
例 6-34 查询讲授课程号为 C5的教师姓名。
程序清单如下:
SELECT TN
FROM T
WHERE TNO=ANY
(SELECT TNO
FROM TC
WHERE CNO='C5')
6.4.2 返回一组值的子查询
2,使用 IN
可以使用 IN代替,=ANY”。
例 6-36 查询讲授课程号为 C5的教师姓名程序清单如下:
SELECT TN
FROM T
WHERE TNO IN
(SELECT TNO
FROM TC
WHERE CNO='C5')
6.4.2 返回一组值的子查询
3,使用 ALL
ALL的含义为全部。
例 6-37 查询其他系中比电力系所有教师工资都高的教师的姓名和工资。
程序清单如下:
SELECT TN,SAL
FROM T
WHERE SAL>ALL
(SELECT SAL
FROM T
WHERE DEPT='电力 ')
AND DEPT!=?电力’
6.4.2 返回一组值的子查询
4,使用 EXISTS
EXISTS表示存在量词,带有 EXISTS的子查询不返回任何实际数据,它只得到逻辑值“真”或“假”。当子查询的的查询结果集合为非空时,外层的 WHERE子句返回真值,否则返回假值。
例 6-38 查询讲授课程号为 C5的教师姓名程序清单如下:
SELECT TN
FROM T
WHERE EXISTS
(SELECT *
FROM TC
WHERE TNO=T.TNO
AND CNO='C5')