第七章、高级数据库查询
内容提要:
1. 掌握一般数据查询功能扩展
2. 掌握查询的并、交、差运算
3.掌握子查询的使用
4.了解其他一些查询功能
第一节 一般数据查询功能扩展
1.1. SELECT语句
//SQL的一般查询语句
SELECT [DISTINCT] [TOP n] select_list
//将查询的结果插入到了一个表中
[INTO new_table]
//需要查询的表
[FROM table_source]
//查询的条件
[WHERE search_conditition]
//对查询的结果进行分组
[GROUP BY group_by_expression]
//指定组或聚合函数的查找条件
[HAVING search_condition]
//对查询的结果进行排序
[ORDER BY order_expression [ASC|DESC]]
//对查询结果结果后面生成汇总数据行
[COMPUTE expression]
1.2.使用TOP限制结果集
TOP n [percent][WITH TIES]
? Top n 前n行
? Top n [percent]前n%行
? [WITH TIES]:包括最后一行取值并列的结果。
例题:
【例1】查询单价最高的前三种商品的商品名、商品类别和单价,包括并列情况。
SELECT TOP 3 WITH TIES GoodsName, GoodsClassName,SaleUnitPrice,FORM Table_Goods a JOIN Table_GoodsClass b
ON a.GoodsClassID=b.GoodsClassID ORDER BY SaleUnitPrice DESC
1.3.使用CASE函数
- 分情况显示不同类型的数据。CASE函数是一种多分支表达式。
- 两种类型:
- 简单CASE函数
- 搜索CASE函数
语法:
CASE
WHEN 布尔表达式1 then 结果表达式1
WHEN 布尔表达式2 then 结果表达式2
……
WHEN 布尔表达式n then 结果表达式n
[ELSE 结果表达式n+1]
END
案例:
分析下列语句的作用(P110)
SELECT a.GoodsID,商品销售类别=CASE
WHEN COUNT(b.GoodsID)>10 THEN ‘热门商品’
WHEN COUNT(b.GoodsID)BETWEEN 5 AND 10 THEN ‘一般商品’
WHEN COUNT(b.GoodsID)BETWEEN 1 AND 4 THEN ‘难销商品’
ELSE ‘滞销商品’
END
FROM Table_Goods a LEFT JOIN Table_SaleBillDetail b
ON a.GoodsID=b.GoodsID GROUP BY a.GoodsID
1.4.将查询结果保存到新表中
SELECT 查询列表序列 INTO
FROM 数据源……(其他行过滤、分组语句)
注意:表名前加#为局部临时表,##为全局临时表,只有表名为永久表。
临时表只能当前查询可用
例子:SELECT * INTO #HD_Customer FROM Table_Customer WHERE ……
第二节 查询结果的并、交、差运算
2.1.并运算
- 并运算(UNION):将多个查询结果合并为一个结果集。。
- 语法:
SELECT 语句1
UNION [ALL]
SELECT 语句2
UNION [ALL]
……
使用UNION注意:
- 要进行合并的查询,SELECT中列数必须相同,语义相同。
- 每个相对应列的数据类型隐式兼容,如char(20)与varchar(40)。
- 合并后结果采用第一个SELECT语句的列标题。
- 若需排序,则GROUP BY语句写在最后一个SELECT之后,且排序的语句是第一个SELECT中的列名。
2.2.交运算
- 交运算:返回同时在两个集合中出现的记录。
- 语法:
SELECT 语句1
INTERSECT
SELECT 语句2
INTERSECT ……
SELECT 语句n
2.3.差运算
- 差运算:返回第一个集合中有而第二个集合中没有的的记录。
- 语法:
SELECT 语句1
EXCEPT
SELECT 语句2
EXCEPT……
SELECT 语句n
第三节 相关子查询
- 子查询是一条包含在另一条SELECT语句里的SELECT语句。外层的SELECT语句叫外层查询,内层的SELECT语句叫内层查询(或子查询)。
- 子查询总是写在圆括号中。
包括子查询的SELECT语句主要采用以下格式中的一种:
(1) WHERE expression [NOT] IN (subquery)
(2) WHERE expression comparison_operator [ANY | ALL]
(3)WHERE [NOT] EXISTS (subquery)
案例:
1、
使用子查询进行基于集合的测试
查询和王晓同地区的人,除了王晓以外
SELECT Cname,Address
FROM Table_Customer
WHERE Address IN(
SELECT Address
FROM Table_Customer
WHERE Cname=‘王晓’)
AND Cname!= ‘王晓’
2、
使用子查询进行比较测试
查询单价最高的商品的名称和单价
SELECT Goodname,SaleUnitPrice
FROM Table_Goods a
WHERE SaleUnitPrice=
(
SELECT MAX(SaleUnitPrice)
FROM Table_Goods
)
3、
使用子查询进行存在性测试
查询购买了单价高于2000元商品额顾客的会员卡号。
SELECT DISTINCT CardID
FROM Table_SaleBill
WHERE EXISTS(
SELECT *
FROM Table_SaleBillDetail
WHERE SaleBillID=Table_SaleBill.SaleBillID
AND UnitPrice>2000
)
第四节 其他形式的子查询
4.1.替代表达式的子查询
在SELECT的选择列表中嵌入了一个只返回一个标量值的子查询。
实例:
SELECT Cname,Address,(
SELECT COUNT(*)
FROM Table_Customer b ON a.CardID=b. CardID
WHERE CustomerID=‘C001’
)AS TotalTimes
FROM Table_Custmer
Where CustomerID=‘C001’
4.2.派生表
- 也称为内联视图,是将子查询作为一个表处理,产生的新表为“派生表”。
实例:
查询至少买了G001和G002两种商品的顾客号和顾客名。
SELECT CustomerID,CName
FROM (
SELECT *
FROM Table_SaleBill a JOIN Table_SaleBillDetail b
ON a.SaleBillID=b. SaleBillID
WHERE GoodsID=‘G001’
) AS T1 JOIN (
SELECT *
FROM Table_SaleBill a
JOIN Table_SaleBillDetail b ON a.SaleBillID=b. SaleBillID
WHERE GoodsID=‘G002’
) AS T2
ON T1.CardID=T2.CardID
JOIN Table_Customer c ON c.CardID=T1. CardID
第五节 其他一些查询功能
5.1.开窗函数
- 在SQL Server 中,一组行被称为一个窗口。
- 与聚合函数一样,开窗函数也是对行集组进行聚合计算,但是它不像普通聚合函数那样每组只返回一个值,开窗函数可以为每组返回多个值,因为开窗函数所执行聚合计算的行集组是窗口。
- 与聚合函数不同的是,开窗函数在聚合函数后增加了一个OVER 关键字。
- 开窗函数的调用格式为:
函数名(列)OVER(选项)- OVER 关键字:表示把函数当成开窗函数而不是聚合函数。
- SQL 标准允许将所有聚合函数用做开窗函数,使用OVER 关键字来区分这两种用法。
实例1:
将OVER字句与聚合函数结合使用
设有课程表Course(Cno,CName,Credit,Semester)查询全部课程的Cno,CName,Semester, Credit信息及其该学期开设课程的总、最高、平均、最低Credit 。
SELECT Cno,CName,Semester ,Credit
SUM(Credit) OVER(PARTITION BY Semester) AS ‘Total’,
AVG(Credit) OVER(PARTITION BY Semester) AS ‘Avg’,
MIN(Credit) OVER(PARTITION BY Semester) AS ‘Min’,
MAX(Credit) OVER(PARTITION BY Semester) AS ‘Max’,
FROM Course
实例2:
将OVER子句与排名函数一起使用
- 排名函数RANK()
RANK() OVER([<partition_by_clause>,…[n]]<order_by_clause>)
- 注意: 排名函数具有不确定性 。
? 排名从1开始,不一定是连续整数。
SELECT OrderID, ProductID, OrderQty
RANK() OVER(PARTITION BY OrderID ORDER BY OrderQty DESC )
AS RANK
FROM OrderDetail
ORDER BY OrderID
其他排名函数
- DENSE_RANK()
排名是连续整数
- NTILE()
将有序分区中的行划分到指定数目的组中,编号从1开始,函数返回此行所属的组的编号。
- ROW_NUMBER()
返回结果集中每个分区内的序列号,每个分区的第一行从1开始。
5.2.公用表表达式
- 公用表表达式(CommonTableExpression,CTE):
将查询结果集指定一个临时名字,这些命名的结果集就是公用表表达式。
- 格式:
WITH <common_table_expression>[,…n]
<common_table_expression>::=
Expression_name[(column_name [,…n])]
AS
(SELECT语句)
实例 :
定义一个统计每个会员购买商品总次数的CTE,并利用CTE查询会员卡号和购买商品的次数。
定义:
WITH BuyCount(CardID,Counts)
AS(SELECT CardID,Count(*)
FROM Table_SaleBill
GROUP BY CardID
)
使用:
AS(
SELECT CardID,Counts
FROM BuyCount
ORDER BY Counts
)
例题:
1、
1.设某数据库中有旅客表A(旅客编号,城市)和旅客表B(旅客编号,城市),现将所有旅客的数据存储这两张表中。请补全如下查询语句,使得该查询语句能查询所有旅客所在的全部的不重复的城市。
SELECT 城市 FROM 旅客表A
( )
SELECT 城市 FROM 旅客表B
答案: UNION
2、
2.设有购买表(顾客号,商品号,购买时间)。现要查询顾客A与顾客B购买的相同商品。有下列查询语句:
Ⅰ.
SELECT 商品号 FROM 购买表 WHERE 顾客号 = 'A'
AND 商品号 IN (SELECT 商品号 FROM 购买表 WHERE 顾客号 = 'B')
Ⅱ.
SELECT 商品号 FROM 购买表 WHERE 顾客号 = 'A'
EXCEPT
SELECT 商品号 FROM 购买表 WHERE 顾客号 = 'B‘
Ⅲ.
SELECT 商品号 FROM 购买表 WHERE 顾客号 = 'A'
INTERSECT
SELECT 商品号 FROM 购买表 WHERE 顾客号 = 'B'
Ⅳ.
SELECT 商品号 FROM 购买表 WHERE 顾客号 = 'A'
UNION
SELECT 商品号 FROM 购买表 WHERE 顾客号 = 'B'
上述语句中,能够实现该查询要求的是( )。
A.仅Ⅰ和Ⅱ
B.仅Ⅰ和Ⅲ
C.仅Ⅰ和Ⅳ
D.仅Ⅲ
答案:B
3、
3.设有选课表(学号,课程号,成绩),现要统计每门课程的选课人数,并将结果保存到新表:选课情况表。下列语句中正确的是( )。
A.
SELECT 课程号, COUNT(*) 选课人数 FROM 选课表 INTO 选课情况表GROUP BY 课程号
B.
SELECT 课程号, COUNT(*) 选课人数 INTO 选课情况表 FROM 选课表 GROUP BY 课程号
C.
SELECT 课程号, COUNT(*) FROM 选课表 INTO 选课情况表(课程号,选课人数)GROUP BY 课程号
D.
SELECT 课程号, COUNT(*) INTO 选课情况表(课程号, 选课人数)
FROM 选课表 GROUP BY 课程号
答案:B
4、
4.设某数据库中有学生表(学号,姓名,所在系)和选课表(学号,课程号,成绩)。现要查询没选课的学生姓名和所在系。下列语句中能够实现该查询要求的是( )。
A.SELECT姓名,所在系FROM学生表a LEFT JOIN选课表b
ON a.学号=b.学号WHERE a.学号IS NULL
B.SELECT姓名,所在系FROM学生表a LEFT JOIN选课表b
ON a.学号=b.学号WHERE b.学号IS NULL
C.SELECT姓名,所在系FROM学生表a RIGHT JOIN选课表b
ON a.学号=b.学号WHERE a.学号IS NULL
D.SELECT姓名,所在系FROM学生表a RIGHT JOIN选课表b
ON a.学号=b.学号WHERE b.学号IS NULL
答案:B
5、
5.设在SQL Server2008中,用户U1在DB1数据库中创建了#Temp表。下列关于#Temp表的说法中,正确的是( )。
A.在所有用户U1发起的连接中,都可以查询#Temp表数据
B.只有在创建#Temp表的连接中才可以查询#Temp表数据
C.在创建#Temp表的连接未断开时,DB1数据库的所有用户都可以查询#Temp表数据
D. 在创建#Temp表的连接断开时,DB1数据库的所有用户仍可以查询#Temp表数据
答案:B
6、
设在采用SQL Server 2008数据库的图书馆应用系统中有三个基本表,表结构如下所示,请用SQL语句完成下列两个查询:
BORROWER:
借书证号 | 姓名 | 系名 | 班级 |
---|---|---|---|
12011106 | 蒋辉文 | 计算机系 | 12-1 |
12011107 | 王丽 | 计算机系 | 12-1 |
12012113 | 范园园 | 信息系 | 12-2 |
…… | …… | …… | …… |
LOANS:
借书证号 | 图书馆登记号 | 借书日期 |
---|---|---|
12011106 | T001001 | 2012.01.02 |
12012113 | T001026 | 2013.02.06 |
…… | …… | …… |
BOOKS:
索书号 | 书名 | 作者 | 图书登记号 | 出版社 | 价格 |
---|---|---|---|---|---|
TP311.1 | 数据库系统 | 李明 | T001001 | 科学 | 19.00 |
TP311.2 | 二级C语言 | 王珊 | T001026 | 人民 | 32.00 |
…… | …… | …… | …… | …… | …… |
(1)检索至少借了5本书的同学的借书证号、姓名、系名和借书数。
(2)检索借书和王丽同学所借图书中的任意一本相同的学生姓名、系名、书名和借书日期。
1、
SELECT LOANS.借书证号,姓名,系名,COUNT(*)
AS 借书数量
FROM BORROWER,LOANS
WHERE BORROWER.借书证号=LOANS.借书证号
GROUP BY LOANS.借书证号
HAVING COUNT(*)>=5;
2、
SELECT 姓名,系名,书名,借书日期
FROM BORROWER,LOANS , BOOKS
WHERE
BORROWER.借书证号=LOANS.借书证号
AND LOANS.图书登记号=BOOKS.图书登记号
AND 索书号 IN
(
SELECT 索书号 FROM BORROWER,LOANS,BOOKS
WHERE BORROW.借书证号=LOANS.借书证号
AND LOANS.图书馆登记号=BOOKS.图书登记号
AND 姓名="王丽"
)
原文地址:https://www.cnblogs.com/shaoyayu/p/12355331.html