1、SQL Server数据库应用与开发第4稿 8 数据的查询、汇总 、统计和分析8. 数据的查询、汇总 、统计和分析本章主题l SELECT语句l 简单的SELECT查询l 设置查询结果的字段名l 关键字ALL和DISTINCT的使用l 查询结果的输出目的地l WHERE子句的条件搜索功能l SELECT的通配符l 字符和通配符冲突时的解决方法l 连接条件设置l 统计运算的高手:聚合函数l 数据分组小计l HAVING子句的使用l ORDER BY子句的使用l 查询名列前茅或落后者l 活用子查询(SubQuery)精彩内容不容错过!这一章是本课程的重点!本章将深入剖析SELECT命令。8.1.
2、SELECT命令SELECT是一个用来从一个或多个表中获取数据的SQL命令。8.2. 简单的SELECT查询如:USE NorthwindSQLSELECT 身份证号码,姓名,电话号码 - 这里是字段列表FROM 飞狐工作室SELECT命令至少包含: 要出现在查询结果中的字段列表,如:身份证号码,姓名,电话号码 字段来自哪些表,如:FROM 飞狐工作室 字段列表也可以是由字段、常量和函数组成的表达式 要列出所有字段,只须用 * 号8.3. 设置查询结果的字段名查询需求请从数据库pubs的authors表,查询出所有作者的代号、姓名、电话号码及住址,而且请使用中文文字作为查询结果的各字段名。解答
3、/* 脚本文件名: Demo91.sql */USE pubsSELECT 作者代号 = au_id, 姓名 = au_fname+au_lname, 电话号码 = phone, 住址 = address FROM authors或 (看看你更喜欢哪一种格式?)/* 脚本文件名: Demo92.sql */USE pubsSELECT au_id AS 作者代号, au_fname+au_lname AS 姓名, phone AS 电话号码, address AS 住址 FROM authors注意: 如果您设置的的字段名包含空格,则须加上单引号SELECT au_fname+au_lname
4、 AS Name of AuthorFROM authors任务:查询teacher表的姓名、性别和生日,列名用中文表示;查询class表的所有班级信息;查询teacher表的教师姓名和年龄。8.4. 关键字ALL和DISTINCT的使用1. 查询需求请列出“飞狐工作室”表中所有员工的雇用日期,但是日期相同者只列出一次即可。USE NorthwindSQLSELECT DISTINCT 雇用日期 FROM 飞狐工作室2. 查询需求请列出“飞狐工作室”表中有哪些部门。USE NorthwindSQLSELECT DISTINCT 部门 FROM飞狐工作室ALL为默认项,显示所有查询到的记录,包括
5、重复项。DISTINCT,对指定字段的内容相同的,仅显示一项。每个SELECT表达式只能有一个DISTINCT关键字。这意味着,DISTINCT是限制整条数据记录都重复者,只显示其中一条,而不是针对单一字段来处理。任务:请列出“章立民工作室”表中有哪些部门。列出teacher表中的教师职称。8.5. 查询结果的输出目的地为什么要讨论查询结果的输出目的地?答:可能希望将查询结果输出到某个存储处以便进行进一步的处理。举例说明INTO子句的用法: 将查询结果存储到当前数据库中的新表MyTmpTable中USE NorthwindSQLSELECT * INTO MyTmpTable FROM 飞狐工
6、作室注:INTO子句会生成相应的表,如果表已存在则提示错误“表已存在”。任务:把teacher表中的教师职称保存到新表教师职称表中。查询员工表中的职称,并存储到新表员工职称表中。8.6. WHERE子句的条件搜索功能1. 查询需求请列出“飞狐工作室”表中目前薪资大于60000的员工。/* 脚本文件名: Demo93.sql */USE NorthwindSQLSELECT 姓名,目前薪资 FROM 飞狐工作室 WHERE 目前薪资 600002. 查询需求请列出“飞狐工作室”表在信息部、行销部和业务部等3个部门任职的员工姓名。/* 脚本文件名: Demo94.sql */USE Northwi
7、ndSQLSELECT 姓名,部门 FROM 飞狐工作室 WHERE 部门 IN (资讯部,行销部,业务部)3. 查询需求请列出“飞狐工作室”表在信息部、行销部和业务部等3个部门以外任职的员工姓名。/* 脚本文件名: Demo95.sql */USE NorthwindSQLSELECT 姓名,部门 FROM 飞狐工作室 WHERE 部门 NOT IN (资讯部,行销部,业务部)4. 查询需求请列出“飞狐工作室”表中,本月出生的员工姓名和出生日期。/* 脚本文件名: Demo910.sql */USE NorthwindSQLSELECT 姓名,出生日期 FROM 飞狐工作室 WHERE MO
8、NTH(出生日期) = MONTH(GETDATE()5. 查询需求请列出“飞狐工作室”表中,年龄大于20岁的每一位员工的姓名。/* 脚本文件名: Demo911.sql */USE NorthwindSQLSELECT 姓名 FROM 飞狐工作室 WHERE DATEDIFF(year,出生日期,GETDATE()20任务:查询章立民工作室中已婚的员工信息;查询“飞狐工作室”表中行销部的员工信息;查询06010111班或者07010211班的学生信息;查询成绩在80分以下的学生选课信息;查询年龄超过50岁的女教师信息;查询出生日期在1970到1980年之间的教师信息。8.7. SELECT的
9、通配符共有5个通配符。*(星号) 用于字段列表,代表源表中的所有的字段/* 脚本文件名: Demo913.sql */USE NorthwindSQL-连接两张表“客户”表和“订货主档”表SELECT * FROM 客户 INNER JOIN 订货主档 ON 客户.客户编号 = 订货主档.客户编号 WHERE 订货主档.订单日期 BETWEEN 08/01/1996 AND 08/31/1996/* 脚本文件名: Demo914.sql */USE NorthwindSQLSELECT 客户.公司名称,订货主档.* FROM 客户 INNER JOIN 订货主档 ON 客户.客户编号 = 订货
10、主档.客户编号 WHERE 订货主档.订单日期 BETWEEN 08/01/1996 AND 08/31/1996%(百分号) 只能用在WHERE子句中,代表0个或0个以上的字符。如:ABC%代表ABC开头的字符串。 百分号通常与运算符LIKE搭配使用。/* 脚本文件名: Demo915.sql */USE NorthwindSQLSELECT 姓名 FROM 飞狐工作室 WHERE 姓名 LIKE %光% -表示查询姓名中包含“光”字的记录任务:查询“飞狐工作室”表中住在北京市的的员工信息;查询教师表中姓杜的教师信息;查询professional表中专业名称包含计算机的专业信息。_(下划线)
11、 只能用在WHERE子句中,代表1个字符。如:_A%代表第二个字符为A的字符串。 下划线通常与运算符LIKE搭配使用。 USE NorthwindSQL SELECT 姓名 FROM 飞狐工作室 WHERE 姓名 LIKE _建_(中括号) 只能用在WHERE子句中,用来限定任何一个单个字符介于指定的范围或集合中。 通常与运算符LIKE搭配使用。/* 脚本文件名: Demo923.sql */USE pubsSELECT au_fname,au_lname FROM authors WHERE au_lname LIKE P-Zinger -表示第一个字符为PZ之间且后五个字符为inger/*
12、 脚本文件名: Demo924.sql */USE NorthwindSQLSELECT 姓名 FROM 飞狐工作室 WHERE 姓名 LIKE ACD张李% -表示什么? ORDER BY 姓名任务:查询学号尾号为1、3、5、7、9的学生信息。(中括号中包含号) 只能用在WHERE子句中,用来限定任何一个单个字符不介于指定的范围或集合中。 通常与运算符LIKE搭配使用。/* 脚本文件名: Demo927.sql */USE pubsSELECT au_fname,au_lname FROM authors WHERE au_fname LIKE H-Kichel -首字母不介于HK之间且后为
13、ichel/* 脚本文件名: Demo930.sql */USE NorthwindSQLSELECT 身份证号码,姓名 FROM 飞狐工作室 WHERE 身份证号码 LIKE ALM% -这个表示什么意思?任务:查询学号尾号不为1、3、5、7、9的学生信息。8.8. 字符和通配符冲突时的解决方法可以使用ESCAPE子句通知SQL Server哪一个字符是常量字符而并非通配符。用专业术语来说,ESCAPE子句所指定的字符称为“转义符”。/* 脚本文件名: Demo920.sql */USE NorthwindSQLSELECT 姓名, 家庭地址 FROM 飞狐工作室 WHERE家庭地址 LIK
14、E %_% ESCAPE -通知符号后的字符并非通配符,即查询住址中带下划线的记录8.9. 连接条件设置本节内容太重要了!看如下代码,如果TableA有M条记录,TableB有N条记录,则查询结果共有MN条记录:SELECT * FROM TableA,TableB或SELECT * FROM TableA CROSS JOIN TableB为了避免出现上述情况,有4种连接类型可以选择: INNER JOIN特点:查询结果仅包含连接表中彼此相对应的数据记录。/* 脚本文件名: Demo933.sql 本例用于查看每一位客户的订货情况但是,并未下订单的客户不会出现在查询结果中!*/USE Nor
15、thwindSQLSELECT 客户.客户编号, 客户.公司名称, 客户.联系人, 客户.电话, 订货主档.订单号码, 订货主档.订单日期, 订货主档.要货日期, 订货主档.送货日期, 订货主档.送货方式, 订货主档.运费, 订货主档.收货人,订货主档.送货地址 FROM 客户 INNER JOIN 订货主档 ON 客户.客户编号 = 订货主档.客户编号更复杂的连接3个表的例子:/* 脚本文件名: Demo934.sql */USE NorthwindSQLSELECT 客户.客户编号,客户.公司名称,订货主档.订单号码, 订货主档.订单日期,订货明细.产品编号,订货明细.单价, 订货明细.数
16、量, 订货明细.折扣 FROM 客户 INNER JOIN 订货主档 ON 客户.客户编号 = 订货主档.客户编号 INNER JOIN 订货明细 ON 订货主档.订单号码 = 订货明细.订单号码任务:查询下了订单的客户信息:客户编号、公司名称、订单号码、订单日期;查询产品信息:产品编号、类别名称;查询学生信息:学号、姓名、班级名称;查询班级信息:班级编号、班级名称、专业名称;查询专业信息:专业编号、专业名称、系名称;列出计算机工程系的专业信息;查询孙晓龙的所有选修课成绩;查询选修了“3dsmax”课程的学生姓名和课程成绩。 LEFT OUTER JOIN(左外连接)特点:查询结果将包含位于关
17、键字LEFT OUTER JOIN左侧源表中的所有数据记录,但是仅包含右侧源表中相应的数据记录。/* 脚本文件名: Demo935.sql 本例用于查看每一位客户的订货情况但是希望并未下订单的客户也出现在查询结果中!*/USE NorthwindSQLSELECT 客户.客户编号, 客户.公司名称, 客户.连络人, 订货主档.订单号码, 订货主档.收货人 FROM 客户 LEFT OUTER JOIN 订货主档 ON 客户.客户编号 = 订货主档.客户编号(加上条件限制试试 WHERE订货主档.订单号码 is NULL) RIGHT OUTER JOIN(右外连接)特点:查询结果将包含位于关键
18、字RIGHT OUTER JOIN右侧源表中的所有数据记录,但是仅包含左侧源表中相应的数据记录。/* 脚本文件名: Demo936.sql 查看每一种产品的销售情况但是希望那些没有人订购的产品数据也在查询结果中出现*/USE NorthwindSQLSELECT 订货明细.订单号码, 订货明细.单价, 订货明细.数量, 订货明细.折扣, 产品资料.产品编号, 产品资料.产品 FROM 订货明细 RIGHT OUTER JOIN 产品资料 ON 订货明细.产品编号 = 产品资料.产品编号(加上条件限制试试 WHERE 订货明细.订单号码 is NULL) FULL OUTER JOIN(全外连接
19、)特点:查询结果将包含位于关键字FULL OUTER JOIN左右两侧源表中的所有数据记录。/* 脚本文件名: Demo938.sql 给表指定别名*/USE NorthwindSQLSELECT a.客户编号, a.公司名称, a.连络人, a.电话, b.订单号码, b.订单日期, b.要货日期, b.送货日期, b.送货方式, b.运费, b.收货人, b.送货地址 FROM 客户 a INNER JOIN 订货主档 b ON a.客户编号 = b.客户编号小技巧:给表指定一个较短的别名,最大的好处是缩减了SELECT语句的长度。范例:1. 查询在1996年7月份采购的北京市客户的基本数
20、据、订单数据、订货明细。/* 脚本文件名: Demo939.sql */USE NorthwindSQLSELECT a.客户编号,a.公司名称, a.地址,a.连络人,a.电话, b.订单号码,b.订单日期, b.运费,b.收货人, c.产品编号,c.单价, c.数量,c.折扣 FROM 客户 a INNER JOIN 订货主档 b INNER JOIN 订货明细 c ON b.订单号码 = c.订单号码 ON a.客户编号 = b.客户编号 WHERE a.地址 LIKE %北京市% AND b.订单日期 BETWEEN 07/01/1996 AND 07/31/19962. 查询出所有曾
21、经在1996年订货的客户公司名称和所订购的产品明细/* 脚本文件名: Demo940.sql */USE NorthwindSQLSELECT a.公司名称,b.订单日期,d.* FROM 客户 a INNER JOIN 订货主档 b INNER JOIN 订货明细 c INNER JOIN 产品资料 d ON d.产品编号 = c.产品编号 ON b.订单号码 = c.订单号码 ON a.客户编号 = b.客户编号 WHERE YEAR(b.订单日期) = 19963. 假如ERNSH公司是我们的忠实客户,我们要查询出该公司在1998年所下的订单,以及负责处理这些客户订单的员工基本数据:/*
22、 脚本文件名: Demo941.sql */USE NorthwindSQLSELECT a.公司名称,b.订单号码,b.订单日期,c.* FROM 客户 a INNER JOIN 订货主档 b INNER JOIN 员工 c ON c.员工编号 = b.员工编号 ON a.客户编号 = b.客户编号 WHERE a.客户编号 = ERNSH AND YEAR(b.订单日期) = 19988.10. 统计运算的高手:聚合函数聚合函数专用于SELECT语句中。 COUNTn 主要用于计算查询结果中的数据条数,通常用COUNT(*)的形式。n 事实上,COUNT()是唯一允许使用通配符作为参数的聚
23、合函数。1. 计算出“飞狐工作室”表中的数据记录条数/* 脚本文件名: Demo942.sql */USE NorthwindSQLSELECT COUNT(*) FROM 飞狐工作室2. 计算出“飞狐工作室”表中有多少员工住在北京市/* 脚本文件名: Demo943.sql */USE NorthwindSQLSELECT COUNT(*) FROM 飞狐工作室 WHERE 住址 LIKE %北京市%3. 计算出“飞狐工作室”表中有年龄介于3040之间的员工有多少/* 脚本文件名: Demo944.sql */USE NorthwindSQLSELECT COUNT(*) FROM 飞狐工作
24、室 WHERE DATEDIFF(yy,出生日期,GETDATE() BETWEEN 30 AND 404. 查询出在1996年7月份下订单的北京市客户有多少位/* 脚本文件名: Demo945.sql */USE NorthwindSQLSELECT COUNT(*) AS 客户数目 FROM 客户 a INNER JOIN 订货主档 b ON a.客户编号 = b.客户编号 WHERE a.地址 LIKE %北京市% AND b.订单日期 BETWEEN 07/01/1996 AND 07/31/1996 MINn 能够计算出最小值。1. 查询出“飞狐工作室”表中,最低的目前薪资是多少。/
25、* 脚本文件名: Demo946.sql */USE NorthwindSQLSELECT MIN(目前薪资) AS 最低薪资 FROM 飞狐工作室注意:利用MIN查询出某一字段的最小值时,并无法同时得知该字段为最小值的数据记录的其他字段内容。2. 查询出“飞狐工作室”表中,年龄最大者是几岁(提供了三种方法)。/* 脚本文件名: Demo947.sql */USE NorthwindSQLSELECT YEAR(GETDATE() - YEAR(MIN(出生日期) AS 最高年龄 FROM 飞狐工作室SELECT DATEDIFF(yyyy,MIN(出生日期),GETDATE() AS 最高年
26、龄 FROM 飞狐工作室SELECT MAX(DATEDIFF(yyyy,出生日期,GETDATE() AS 最高年龄 FROM 飞狐工作室 MAXn 能够计算出最大值。 AVGn 能够计算出平均值。1. 计算出“飞狐工作室”表中员工的平均年龄/* 脚本文件名: Demo951.sql */USE NorthwindSQLSELECT AVG(DATEDIFF(yyyy,出生日期,GETDATE() AS 平均年龄 FROM 飞狐工作室 SUMn 求和。1. 计算出所有客户的采购总金额/* 脚本文件名: Demo952.sql */USE NorthwindSQLSELECT 客户采买总金额
27、= SUM(单价*数量*(1-折扣) FROM 订货明细聚合函数注意事项: 可以将查询结果存储到一个变量中/* 脚本文件名: Demo953.sql */USE NorthwindSQLDECLARE AverageSalary money- 将计算所得的平均薪资储存至变数 AverageSalary 中SELECT AverageSalary = AVG(目前薪资) FROM 飞狐工作室/* STR (float_expression , length ,decimal ),返回由数字数据转换来的字符数据。*/PRINT 薪资大于平均薪资 +STR(AverageSalary,10,4)+
28、的员工:PRINT REPLICATE(-,35)SELECT 姓名,目前薪资 FROM 飞狐工作室 WHERE 目前薪资 AverageSalary 同一SELECT语句中,可以分别使用不同的聚合函数/* 脚本文件名: Demo954.sql */USE NorthwindSQLSELECT MAX(目前薪资) AS 最高薪资, -看看这种设定列标题的方式 MIN(目前薪资) AS 最低薪资, AVG(目前薪资) AS 平均薪资, SUM(目前薪资) AS 薪资总额 FROM 飞狐工作室 聚合函数中允许包含DISTINCT关键字,用于排除重复行。1. 计算出1996年8月份的发票开给了几位客
29、户。/* 脚本文件名: Demo955.sql */USE NorthwindSQLSELECT COUNT(DISTINCT 客户编号) AS 客户数目 FROM 订货主档 WHERE 订单日期 BETWEEN 08/01/1996 AND 08/31/1996任务:统计teacher表中职称为讲师的教师人数;查询学生的入学平均分数、最低分、最高分;查询学号为0601011101的学生选课门数;查询学生张劲的选课门数;查询学生张劲选修课程的最高分、最低分、平均分。8.11. 数据分组小计利用GROUP BY子句,可以根据一个或多个组的值将查询中的数据记录分组。1. 计算出员工“飞狐工作室”表
30、中,各个部门的薪资最高值、薪资最小值、薪资平均值及人数。/* 脚本文件名: Demo956.sql */USE NorthwindSQLSELECT 部门, COUNT(*) AS 部门员工人数, MAX(目前薪资) AS 部门最高薪资, MIN(目前薪资) AS 部门最低薪资, AVG(目前薪资) AS 部门平均薪资 FROM 飞狐工作室 GROUP BY 部门任务:统计teacher表中各类职称的教师人数;统计各课程的最高分、最低分、平均分。2. 计算出各个客户的采购次数和采购总金额。/* 脚本文件名: Demo957.sql */USE NorthwindSQLSELECT a.公司名称
31、, COUNT(DISTINCT b.订单号码) AS 采购次数, SUM(c.单价 * c.数量 * (1 - c.折扣) AS 采购总金额 FROM 客户 a INNER JOIN 订货主档 b INNER JOIN 订货明细 c ON b.订单号码 = c.订单号码 ON a.客户编号 = b.客户编号 GROUP BY a.客户编号,a.公司名称3. 查询出每一位业务人员的销售总数量。/* 脚本文件名: Demo958.sql */USE NorthwindSQLSELECT a.员工编号,a.姓名, SUM(c.数量) AS 销售总数 FROM 员工 a INNER JOIN 订货主
32、档 b INNER JOIN 订货明细 c ON b.订单号码 = c.订单号码 ON a.员工编号 = b.员工编号 GROUP BY a.员工编号,a.姓名4. 查询出每一位业务人员的销售总数,同时列出那些比他或她销售还多的业务员数及平均销售数目。/* 脚本文件名: Demo959.sql */EXEC sp_dboption NorthwindSQL,select into/bulkcopy,TRUE -设为true能加快select into的处理速度USE NorthwindSQL-首先,生成一张aMount表,包含每一位业务人员的销售总数SELECT a.员工编号,a.姓名,SUM
33、(c.数量) AS 销售总数 INTO aMount FROM 员工 a INNER JOIN 订货主档 b INNER JOIN 订货明细 c ON b.订单号码 = c.订单号码 ON a.员工编号 = b.员工编号 GROUP BY a.员工编号,a.姓名 SELECT a.员工编号, a.姓名,a.销售总数, COUNT(b.员工编号) AS 业绩比此人好之业务员的人数, AVG(b.销售总数) AS 业绩比此人好之业务员的平均销售总数 FROM aMount a inner join aMount b ON a.销售总数 30000-不可以用HAVING 部门的平均薪资 30000任
34、务:查询选修了选修4门以上(包括4门)选修课的学生;查询订单数查过10张的客户。2. 查询出“飞狐工作室”表中,有哪些员工的姓名是跟别人相同的,而且同样采用某一姓名者又有多少人。/* 脚本文件名: Demo962.sql */USE NorthwindSQLSELECT 姓名 AS 重复的姓名, COUNT(*) AS 重复的人数 FROM 飞狐工作室 GROUP BY 姓名 Having COUNT(*) 13. 计算出订单超过10张的各家客户的订单数目,及其采购总金额。/* 脚本文件名: Demo963.sql */USE NorthwindSQLSELECT a.公司名称, COUNT(
35、DISTINCT b.订单号码) AS 订单张数, SUM(c.单价 * c.数量 * (1 - c.折扣) AS 采购总金额 FROM 客户 a INNER JOIN 订货主档 b INNER JOIN 订货明细 c ON b.订单号码 = c.订单号码 ON a.客户编号 = b.客户编号 GROUP BY a.公司名称 HAVING COUNT(DISTINCT b.订单号码) 108.13. ORDER BY 子句的使用利用ORDER BY子句,可以根据一个或多个字段的数据排序查询出的结果。1. 按照薪资所得的高低顺序,列出“飞狐工作室”表中所有员工的姓名、性别和薪资。/* 脚本文件名
36、: Demo964.sql */USE NorthwindSQLSELECT 姓名, 性别 = CASE 性别 WHEN 0 THEN 女 WHEN 1 THEN 男 END, 目前薪资 FROM 飞狐工作室 ORDER BY 目前薪资 DESC /可用ORDER BY 3 DESC2. 将“飞狐工作室”表中各部门的平均薪资由低到高列出来。/* 脚本文件名: Demo965.sql */USE NorthwindSQLSELECT 部门, AVG(目前薪资) AS 平均薪资 FROM 飞狐工作室 GROUP BY 部门 ORDER BY 2 -可以是order by 平均薪资 -也可以是ord
37、er by AVG(目前新资)3. 列出“飞狐工作室”表中所有员工的隶属部门、员工姓名、性别和薪资,按部门、性别(降序)、目前薪资(升序)来排列。/* 脚本文件名: Demo966.sql */USE NorthwindSQLSELECT 部门, 姓名, 性别 = CASE 性别 WHEN 0 THEN 女 WHEN 1 THEN 男 END, 目前薪资 FROM 飞狐工作室 ORDER BY 部门,性别 DESC,目前薪资 ASC任务:查询入学成绩在450分以上的学生信息,并且按照学生入学成绩从高到低排序;查询选修了3dsmax课程的学生姓名和成绩,并按照成绩降序排列。4. 计算出每一位客户
38、的采购次数和采购总金额。先按照采购次数由多到少排列,而采购次数相同者,则再按照采购总金额由低到高排列。/* 脚本文件名: Demo967.sql */USE NorthwindSQLSELECT a.公司名称, COUNT(DISTINCT b.订单号码) AS 采购次数, SUM(c.单价 * c.数量 * (1 - c.折扣) AS 采购总金额 FROM 客户 a INNER JOIN 订货主档 b INNER JOIN 订货明细 c ON b.订单号码 = c.订单号码 ON a.客户编号 = b.客户编号 GROUP BY a.公司名称 ORDER BY采购次数DESC, 采购总金额8.14. 查询名列前茅或落后者先利用ORDER BY排序,然后