实验四 数据库的组合查询和统计查询
以下通过几个实例来演示sql语句的基本查询和多表联查,以及统计查询
假设目前已经创建好名成为’JXGL’的数据库,并且已经存在了三张表,分别是’S’表,保存学生的基本信息、’C’表,保存课程信息、’SC’表,保存学生的选课以及成绩信息,然后可执行下列的操作。
- 基本查询
- SELECT查询语句
--查询所有的学生的学号和姓名
USE JXGL
SELECT SNO,SNAME FROM S
- 简单查询
--查询所有的学生的姓名,学号,所在系
SELECT SNAME,SNO,SDEPT FROM S
--查询全体学生的详细信息
SELECT * FROM S
--前一个语句等价于:
SELECT SNO,SNAME,SEX,AGE,SDEPT FROM S
--查询经过计算的值
SELECT SNAME, YEAR(GETDATE())-AGE FROM S
--查询全体学生的姓名、出生年份和所在院系,要求用小写字母表示所有系名
SELECT SNAME,'Year of Birth: ' ,Year(GETDATE())-AGE,LOWER(SDEPT) FROM S
--定义列别名改变查询结果的列标题对目标表达式有很大用处
SELECT SNAME,'Year of Birth:' AS 'BIRTH',YEAR(GETDATE())-AGE AS 'BIRTHDAY',LOWER(SDEPT) AS 'DEPATEMENT' FROM S
- 带有WHERE子句的查询
--查询‘软件工程’专业的学生的姓名
SELECT SNAME FROM S WHERE SDEPT ='软件工程'
--查询所有年龄在20岁以下的学生的姓名和年龄
SELECT SNAME,AGE FROM S WHERE AGE<20
--查询考试成绩有不及格的学生的学号
SELECT SNO FROM SC WHERE GRADE<60
--确定范围
--查询年龄在20-23之间的学生姓名、系别和年龄
SELECT SNAME,SDEPT,AGE FROM S WHERE AGE BETWEEN 20 and 23
--确定集合
--查询‘软件工程’,‘计算机科学与技术’,‘小学教育专科’的学生姓名和性别
SELECT SNO,SNAME,SEX FROM S WHERE SDEPT IN('软件工程',' 计算机科学与技术 ',' 小学教育专科班 ')
--字符匹配
--运算符LIKE可以用来进行字符串匹配。一般语法如下
-- [NOT] LIKE <'匹配串'>'<换码字符>']
--查找与属性列值与<匹配串>相匹配的元组。<匹配串>可以是一个完整的字符串,也可以含有通配符%和_ %是通配任意长度,_通配单一长度
--查询姓刘的学生的姓名,学号信息
SELECT SNO,SNAME FROM S WHERE SNAME LIKE '%刘%'
--查询姓李且全名为3个汉字的学生的姓名
SELECT SNO,SNAME FROM S WHERE SNAME LIKE '李__'
--查询所有不姓李的学生的姓名
SELECT SNO,SNAME FROM S WHERE SNAME NOT LIKE '李--'
--涉及空值的查询
SELECT SNO,CNO FROM SC WHERE GRADE IS NULL --分数GRADE是空值
--多重条件查询
--查询计算机科学班年龄在22岁以下的学生的姓名
SELECT SNO,SNAME,AGE FROM S WHERE AGE<22 AND SDEPT =' 计算机科学与技术 '
--查询计科,软工,新能源中学生 姓名 性别
SELECT SNAME,SEX,SDEPT FROM S WHERE SDEPT = ' 计算机科学与技术 ' OR SDEPT = '软件工程' OR SDEPT = ' 新能源科学与工程 '
- 带有ORDER BY 子句的查询
--默认ASC升序排列,或者DESC降序排列
--查询课程号为C11的学生成绩,结果按照降序排列
SELECT SNO,GRADE FROM SC WHERE CNO = 'C11' ORDER BY GRADE DESC
--查询全体学生情况,结果按照所在系的系部名升序排列ASC,系部内部按照学生的年龄降序排列DESC
SELECT * FROM S ORDER BY SDEPT ,AGE DESC
5)带有GROUP BY 子句的查询
--查询S表中的男生,女生数量
SELECT SEX AS '性别',COUNT (*) AS '人数' FROM S GROUP BY SEX
--查询选修每门课程的课程号及参加该门考试的学生的总人数
SELECT CNO,COUNT(*) AS '人数' FROM SC WHERE GRADE IS NOT NULL GROUP BY CNO
--查询出选课人数超过8人的课程号
SELECT CNO AS '课程号',COUNT (SNO) AS '人数' FROM SC GROUP BY CNO HAVING COUNT (SNO)>=8
--查询选修超过3门课程的学生的学号
SELECT SNO FROM SC GROUP BY SNO HAVING COUNT(*)>3
6)输出结果选项
--输出前n行
--从SC表中输出学习'C1'课程的学生的成绩在前三名的学号和成绩
SELECT TOP 3 SNO,GRADE FROM SC WHERE CNO = 'C1' ORDER BY GRADE DESC
--在SC表中查询总分排在前面20%的学生的学号和总分
SELECT TOP 20 PERCENT SNO,SUM(GRADE) AS '总分' FROM SC GROUP BY SNO ORDER BY SUM(GRADE) DESC
--将SC中的不及格的学生的学号都存在GRADE_NPASS表中
SELECT DISTINCT(SNO)INTO GRADE_NPASS FROM SC WHERE GRADE <60
7)联合查询
---UNION(并) INTERSECT(交) EXCEPT(差)
--集合并运算
--查询选修了C1或者C2的学生的学号
SELECT SNO FROM SC WHERE CNO ='C1' UNION SELECT SNO FROM SC WHERE CNO ='C2'
--集合交运算
--查询选修了C1又选修了C3的学生的名单
SELECT SNO FROM SC WHERE CNO ='C1' INTERSECT SELECT SNO FROM SC WHERE CNO='C3'
--集合差运算
--查询选修了C1但是没有选修C3的学生的名单
SELECT SNO FROM SC WHERE CNO = 'C1' EXCEPT SELECT SNO FROM SC WHERE CNO='C3'
- 多表查询
- 连接查询
--连接查询是指在两个或两个以上的表中对符合某些条件的元组进行连接查询的操作
--早期FORM ...WHERE...已经舍弃,现在使用 INNER JOIN
--学生的基本信息情况放在S表中,学生的选课信息放在SC表中,本查询是通过公共属性SNO实现的
SELECT S.*,SC.* FROM S INNER JOIN SC ON S.SNO =SC.SNO
--查询计科班的学生所选的课程号和平均成绩
SELECT SC.CNO,ROUND(AVG(SC.GRADE),2) AS 'AVERAGE' FROM S INNER JOIN SC ON S.SNO = SC.SNO AND S.SDEPT= '计算机科学与技术 ' GROUP BY CNO
--在SC表中查询选修了'C4'课程的分数高于20175104001的同学的所有元组,并按照成绩降序排列
SELECT A.SNO,A.CNO,A.GRADE FROM SC A INNER JOIN SC B ON A.CNO='C4' AND A.GRADE>B.GRADE AND B.SNO = '20175104017' AND B.CNO = 'C4'
--查询90分以上学生的学号,姓名,选修课程号,选修课程名和成绩
SELECT S.SNO,S.SNAME,C.CNAME,SC.GRADE FROM S JOIN SC ON S.SNO=SC.SNO AND GRADE >=90 JOIN C ON SC.CNO = C.CNO
----外连接
---左外连接
--对左边的表不加限制,当左边的表元组与右边表元组不匹配时,与右边表相对应的列值为NULL
--查询每个学生及其选修课程的成绩情况
SELECT S.*,CNO,GRADE FROM S LEFT JOIN SC ON S.SNO =SC.SNO
--查询所有学生可能的选课情况
SELECT S.SNO,S.SNAME,C.CNAME FROM S CROSS JOIN C
- 子查询
--无关子查询
--(1.查询‘李欢洋’所在系名)
SELECT SDEPT FROM S WHERE SNAME ='李欢洋' --先分步完成此查询,然后构造子查询。确定‘李欢洋’所在系名
--(2.查询所有在‘软件工程系学习的学生’)
SELECT SNO,SNAME,SDEPT FROM S WHERE SDEPT='软件工程'
--将第一步查询嵌入第二步查询的条件中,构造嵌套查询如下
SELECT SNO,SNAME,SDEPT FROM S WHERE SDEPT IN
(SELECT SDEPT FROM S WHERE SNAME='李欢洋')
--该查询也可以用自身连接来完成
SELECT B.SNO,B.SNAME,B.SDEPT FROM S AS A JOIN S AS B ON A.SDEPT =B.SDEPT AND A.SNAME = '李欢洋'
--查询选修了'C3'号课程的学生的姓名和所在专业
SELECT SNAME,SDEPT FROM S WHERE SNO in (SELECT SNO FROM SC WHERE CNO ='C3')
--查询其他系比计科班中某一学生的年龄小的人姓名学号
SELECT SNAME ,AGE FROM S WHERE AGE<(SELECT MAX(AGE) FROM S WHERE SDEPT ='计算机科学与技术')AND SDEPT <>'计算机科学与技术'
--相关子查询
--父查询每循环一次,子查询都会重新被执行一次,并且每次父查询都会将查询引用值传给子查询
--如果子查询的任何元组与其匹配,父查询就会返回结果元组
--再回到第一步,直到处理完父表的每一个元组
--1)带有比较运算符的子查询
--将一个表达式的值与子查询返回的单个值进行比较。如果比较的结果为TRUE,则返回TRUE
--查询每个学生比他的平均成绩高的所有成绩,并输出这些学生的学号,课程号,成绩
SELECT SNO,CNO,GRADE FROM SC AS A WHERE GRADE >=(SELECT AVG(GRADE) FROM SC AS B WHERE A.SNO=B.SNO)
--2)带有EXISTS的子查询
--查询所有选修了'C2'的学生的名单
SELECT SNAME FROM S WHERE EXISTS (SELECT * FROM SC WHERE SC.SNO=S.SNO AND SC.CNO ='C2')
--表数据维护的子查询
--对每一个系,求学生平均年龄,并把结果存入数据库
--首先在数据库中建立一个新表,其中一列存放系名,另一列存放的是相应的学生的平均年龄。
CREATE TABLE DEPT_AGE(SDEPT CHAR(15),AVG_AGE REAL)
--然后对S表按系分组求平均年龄,再把系名和平均年龄存入新表中
INSERT INTO DEPT_AGE(SDEPT,AVG_AGE) SELECT SDEPT ,AVG(AGE) FROM S GROUP BY SDEPT
--带子查询的删除语句
--删除软件工程系的所有学生的选课记录 千万不能用,下面仅作演示语句,数据库中操作万不得已不能用delete,常用update代替
DELETE FROM SC WHERE '软件工程'=(SELECT SDEPT FROM S WHERE S.SNO=SC.SNO)
--带子查询的修改语句
--将软件工程学生成绩提高5%
UPDATE SC SET GRADE =GRADE +GRADE *0.05 WHERE '软件工程'=(SELECT SDEPT FROM S WHERE S.SNO=SC.SNO)