ACCP V4.01
第五章数据查询 (2)
ACCP V4.02
回顾
数据查询将按照一定的条件对表的的记录进行逐行筛选,
然后把符合要求的组合成“记录集”返回给查询的用户,
记录集的结构类似于表结构
可以在查询中使用 AS子句或者 =重命名列名
判断一行中的数据项是否为空,使用 IS NULL
使用 TOP子句可以限制查询返回的行数
ORDER BY子句用来对查询的结果进行排序,缺省按照升序排列,也可以按降序( DESC)来排列,还可以按照多列来排序
在查询语句中,可以使用常量、表达式和运算符
在查询中使用函数,能够像在程序中那样处理查询得到的数据项
ACCP V4.03
目标
使用 LIKE,BETWEEN,IN进行模糊查询
在查询中使用聚合函数
使用 GROUP BY进行分组查询
进行多表联结查询
ACCP V4.04
模糊查询 — LIKE
查询时,字段中的内容并不一定与查询内容完全匹配,只要字段中 含有 这些内容
SELECT SName AS 姓名 FROM Students
WHERE SName LIKE '张 %'
姓名张果老张飞张扬出去思考:以下的 SQL语句:
SELECT * FROM 数据表
WHERE 编号 LIKE '00[^8]%[A,C]%‘
可能会查询出的编号值为 ( )。
A,9890ACD
B,007_AFF
C,008&DCG
D,KK8C
ACCP V4.05
模糊查询 — IS NULL
把某一字段中内容为 空 的记录查询出来
SELECT SName As 姓名 SAddress AS 地址
FROM Students WHERE SAddress IS NULL
姓名 地址张果老 NULL
李寻欢 NULL
令狐冲 NULL
程灵素 NULL
… …
猜一猜:把 Students表中某些行的 SAddress字段值删掉后:
—— 使用 IS NULL能查询出来这些数据行吗?
—— 怎么查询出这些行来?
ACCP V4.06
模糊查询 — BETWEEN
把某一字段中内容 在特定范围内 的记录查询出来
SELECT StudentID,Score FROM SCore WHERE Score
BETWEEN 60 AND 80
StudentID Score
7 77
8 61
11 76
17 64
… …
ACCP V4.07
模糊查询 — IN
把某一字段中内容与所列出的 查询内容列表 匹配的记录查询出来
SELECT SName AS 学员姓名,SAddress As 地址 FROM
Students WHERE SAddress IN('北京 ','广州 ','上海 ')
学员姓名 地址李扬 广州于紫电 上海李青霜 北京司马弓 上海
… …
ACCP V4.08
问题成绩表中存储了所有学员的成绩,我想知道:
学员的总成绩、平均成绩、有成绩的学员总共有多少名怎么办?
ACCP V4.09
聚合函数 -1
SUM
AVG
SELECT SUM(ytd_sales) FROM titles WHERE type = 'business'
SELECT SUM(ytd_sales),Price
FROM titles WHERE type = 'business' ×
SELECT AVG(SCore) AS 平均成绩
From Score WHERE Score >=60
ACCP V4.010
聚合函数 -2
MAX,MIN
COUNT
SELECT AVG(SCore) AS 平均成绩,MAX (Score) AS 最高分,
MIN (Score) AS 最低分 From Score WHERE Score >=60
SELECT COUNT (*) AS 及格人数 From Score
WHERE Score>=60
ACCP V4.011
问题如果不是统计所有人所有课程的总成绩而是想求每 一门课 的 平均 绩或者 某个人 的所有课的总成绩怎么办?
ACCP V4.012
分组汇总这三个数取平均值第 4-6分数取平均值最后 三个数取平均值有一个学员参加考试
ACCP V4.013
分组查询 — GROUP BY
SELECT CourseID,AVG(Score) AS 课程平均成绩
FROM Score
GROUP BY CourseID
ACCP V4.014
分组查询 — 思考
SELECT StudentID,CourseID,AVG(Score) AS 课程平均成绩
FROM Score
GROUP BY CourseID
思考:执行以下的 T-SQL:
—— 结果如何?
ACCP V4.015
分组查询 — 多列分组第一次内部测试成绩第二次内部测试成绩第三次内部测试成绩补考成绩怎么样来统计每次的内部测试不同学员的成绩?
ACCP V4.016
分组查询 — 再看看内部测试成绩还要把这个加上取平均
StudentID和 CourseID的组合存在重复 ……
需要按照这两个来进行分组,避免 StudentID和 CourseID 同时一样
ACCP V4.017
分组查询 — 多列分组
SELECT StudentID AS 学员编号,CourseID AS 内部测试,
AVG(Score) AS 内部测试平均成绩
FROM Score
GROUP BY StudentID,CourseID
ACCP V4.018
分组查询 — 问题在以上统计内部测试成绩的基础上,
如果只想看补考的学员的成绩,怎么办?
ACCP V4.019
分组查询 — 再看看增加条件:要求该学员的 CourseID在分组内出现过一次以上 ……
SELECT StudentID AS 学员编号,CourseID AS 内部测试,
AVG(Score) AS 内部测试平均成绩
FROM Score
GROUP BY StudentID,CourseID
ACCP V4.020
分组查询 — HAVING
SELECT StudentID AS 学员编号,CourseID AS 内部测试,
AVG(Score) AS 内部测试平均成绩
FROM Score
GROUP BY StudentID,CourseID
HAVING COUNT(Score)>1
ACCP V4.021
分组查询 — 对比
WHERE GROUP BY HAVING
WHERE子句从数据源中去掉不符合其搜索条件的数据
GROUP BY子句搜集数据行到各个组中,统计函数为各个组计算统计值
HAVING子句去掉不符合其组搜索条件的各组数据行
ACCP V4.022
分组查询 — 思考
SELECT 部门编号,COUNT(*)
FROM 员工信息表
WHERE 工资 >= 2000
GROUP BY 部门编号
HAVING COUNT(*) > 1
思考:分析以下 T-SQL的含义
ACCP V4.023
多表联结查询 — 问题学员内部测试成绩查询的每次显示的都是学员的编号信息,
因为该表中只存储了学员的编号;
实际上最好显示学员的姓名,而姓名存储在学员信息表;
如何同时从这两个表中取得数据?
ACCP V4.024
多表联结查询 — 分类
内联结 (INNER JOIN)
外联结
—— 左外联结 (LEFT JOIN)
—— 右外联结 (RIGHT JOIN)
—— 完整外联结 (FULL JOIN)
交叉联结 (CROSS JOIN)
ACCP V4.025
SELECT S.SName,C.CourseID,C.Score
From Score AS C
INNER JOIN Students AS S
ON C.StudentID = S.SCode
Score
StudentsID CourseID Score
1
2
2
3
001
001
002
002
97
89
67
76
3 003 81
猜一猜:这样写,返回的查询结果是一样的吗?
SELECT S.SName,C.CourseID,C.Score
From Students AS S
INNER JOIN Score AS C
ON C.StudentID = S.SCode
再猜一猜:以下返回多少行?
SELECT S.SName,C.CourseID,C.Score
From Students AS S
INNER JOIN Score AS C
ON C.StudentID <> S.SCode
多表联结查询 — 内联结 -1
Stundents
SName
梅超风陈玄风陆乘风曲灵风
SCode
1
2
3
4
查询结果
SName
梅超风陈玄风陈玄风陆乘风
CourseID Score
001
001
002
002
97
89
67
76
陆乘风 003 81
ACCP V4.026
多表联结查询 — 内联结 -2
SELECT Students.SName,Score.CourseID,Score.Score
FROM Students,Score
WHERE Students.SCode = Score.StudentID
ACCP V4.027
多表联结查询 — 三表联结
SELECT
S.SName AS 姓名,CS.CourseName AS 课程,C.Score AS 成绩
FROM Students AS S
INNER JOIN Score AS C ON (S.SCode = C.StudentID)
INNER JOIN Course AS CS ON (CS.CourseID = C.CourseID)
ACCP V4.028
Score
StudentsID CourseID Score
1
2
2
3
001
001
002
002
97
89
67
76
3 003 81
多表联结查询 — 左外联结
Stundents
SName
梅超风陈玄风陆乘风曲灵风
SCode
1
2
3
4
查询结果
SName
梅超风陈玄风陈玄风陆乘风
CourseID Score
001
001
002
002
97
89
67
76
陆乘风 003 81
曲灵风 NULL NULL
SELECT S.SName,C.CourseID,C.Score
From Students AS S
LEFT JOIN Score AS C
ON C.StudentID = S.SCode
猜一猜:这样写,返回的查询结果是一样的吗?
SELECT S.SName,C.CourseID,C.Score
From Score AS C
LEFT JOIN Students AS S
ON C.StudentID = S.SCode
ACCP V4.029
多表联结查询 — 右外联结
SELECT Titles.Title_id,Titles.Title,Publishers.Pub_name
FROM titles
RIGHT OUTER JOIN Publishers
ON Titles.Pub_id = Publishers.Pub_id
ACCP V4.030
案例分析 1— 要求
在数据库表中,数据行位置并不重要,但是一个单位中要根据奇数行和偶数行的数据来汇总,在这个汇总的基础上再得到一个数值,因此,要查询数据库表的奇数行和偶数行的总数
数据库表名,TBL
字段名,A
主键字段,IDKEY(标识列,种子,1;增长量,1)
ACCP V4.031
案例分析 1— 分析
只能依靠标识列的值来进行判断和选取
因为数据行可能存在增加、修改和删除,因此标识列的数据值并不“完全可靠”,例如标识列值为 3,并不一定是第三行,因为如果第二行被删除了,它就是第二行,实际上也是偶数行
根据我们前面使用过的 SELECT…INTO,可以创建一张新表,顺便创建新的标识列,再在新的标识列上执行奇偶判断
奇数判断依据:标识列值 %2不等于 0;偶数判断依据:标识列值 %2等于 0
ACCP V4.032
案例分析 1— T-SQL
SELECT A,IDENTITY(int,1,1) AS ID
INTO TEMPTABLE
FROM TBL
SELECT SUM(A) AS 奇数列汇总
FROM TEMPTABLE
WHERE ID%2 <> 0
SELECT SUM(A) FROM AS 偶数列汇总
FROM TEMPTABLE
WHERE ID%2 = 0
ACCP V4.033
案例分析 2— 要求
一家银行发行了新的信用卡,刚开始的时候推广得很好,
但是逐渐废卡也越来越多(卡上的余额少于 2元,并且用户长时间不使用该卡),因此银行在二月份把这些少于 2元的卡从都数据库表中删除了,但是很快问题就来了,用户发现他的卡再也不能使用而投诉,因此只能再把这些卡恢复。
编写 SQL,把 CardID为 23,30等在子表中没有的记录插入到子表中,插入的数据 Score项值为 2……
ACCP V4.034
案例分析 2— 分析
这是一个数据插入的操作,因此要使用 INSERT语句来进行
这种方式的数据插入,不是固定的数据项,而是从其它表中筛选数据 再插入,因此要使用到 INSERT INTO…SELECT 结构
插入的数据项是子表中没有的,需要找到子表中没有的这些数据,我 们可以把整个语句的 INSERT(前半部分)不考虑,先只考虑
SELECT(后半部分),SELECT的任务就是找出两个表中不同的项
在前面的联结查询中,使用 INNER JOIN…ON 可以找出相同的项,编写以下 T-SQL:
SELECT M.CardID,2 FROM M
INNER JOIN S ON (S.CardID<>M.CardID)
以上把,=”简单地改为,<>”,不能找出不同的项,所找到的项比原来的要多很多,因为两个表之间是进行“交叉”对比的,而不是一一对 比,所以会对比出很多“不同”的项来;因此,这种方法不可行
考虑我们在上面的左外连接查询,能够查询出左表中存在而相关表不 存在的数据项
最后,子表中不存在的数据项,可以再加 WHERE条件来进行筛选,
S.CardID IS NULL可以判断其是否存在子表中存在
ACCP V4.035
案例分析 2— T-SQL
INSERT INTO S (S.CardID,S.Score)
SELECT M.CardID,2
FROM M
LEFT JOIN S
ON (S.CardID=M.CardID)
WHERE S.CardID IS NULL
ACCP V4.036
总结
使用 LIKE,BETWEEN,IN关键字,能够进行模糊查询 —
— 条件不明确的查询
聚合函数能够对列生成一个单一的值,对于分析和统计通常非常有用
分组查询是针对表中不同的组,分类统计和输出,
GROUP BY子句通常会结合聚合函数一起来使用
HAVING子句能够在分组的基础上,再次进行筛选
多个表之间通常使用联结查询
最常见的联结查询是内联结( INNER JOIN),通常会在相关表之间提取引用列的数据项