一、select 语句的一般语法。
数据查询功能是指根据用户的需要以一种可读的方式从数据库中提取数据,查询功能是数据库的核心操作。
SQL语言提供了SELECT动词进行数据的查询,该语句具有灵活的使用方式和丰富的功能,可以实现数据的查询、统计、分组、汇总和排序等多种功能。
SELECT 语句的语法一般格式为:
SELECT [ALL|DISTINCT] <目标列表达式> [别名] [ ,<目标列表达式> [别名]] …
FROM <表名或视图名> [别名] [ ,<表名或视图名> [别名]] …
[WHERE <条件表达式>]
[GROUP BY <列名1> [HAVING <条件表达式>]]
[ORDER BY <列名2> [ASC|DESC]
解析:SELECT子句:指明要检索的结果集的目标列。
FROM子句:指明数据源,即从哪(几)个表(视图)中进行数据检索,表(视图)间用逗号分隔。
WHERE子句(行条件语句):过滤FROM子句中给出的数据源中的数据,通过条件表达式限制查询必须要满足的条件。
GROUP BY语句(分组子句):对满足WHERE子句的行指明按照GROUP BY子句中所指定的某个(几个)列的值对整个结果集进行分组。
ORDER BY(排序子句):对查询返回的结果集进行排序。
二、简单查询。
简单查询是指仅涉及一个数据库表或者视图的查询,也称单表查询,是一种最简单的查询操作。
1、选择表中若干列(实际上对应于关系运算中的投影运算)
1.1 查询指定列
--查询全体学生的姓名、学号、所在系。
select sname,sno,sdept from student
1.2 查询全部列
--查询全体学生的详细记录 select sno,sname,ssex,sage,sdept from student 或 select * from student
1.3 查询经过计算的列
--查全体学生的姓名及其出生年份 select sname,2012-sage from student /*假定当年的年份为2012年*/ --查询全体学生的姓名、出生年份和所有系,要求用小写字母表示所有系名 select sname,2012-sage,lower(sdept) from student
1.4 对列起别名(用于表示该列的含义)
--对上述中的2012-sage起别名 select sname,2012-sage as brthdate from student 或者 select sanme,birthdate=2012-sage from student
1.5 引用字面值(也称常量值)
--该列作用是对2012-sage的说明 select sname,"Year of Birth",2012-sage from student
2、选择表中若干元组
2.1 用于消除重复行的 DISTINCT 谓词,如果没有指定DISTINCT关键词,则缺省为ALL
--查询选修了课程的学生学号 select sno from sc 等价于: select all sno from sc --指定DISTINCT关键词,去掉表中重复的行 select distinct sno from sc
2.2 条件限制。可通过 WHERE条件(行条件)限制,也可通过 HAVING条件(组条件)限制
WHERE子句常用的查询条件谓词如下图:【总结出的下图是很好理解的】
2.2.1 比较运算符的使用
--查询考试成绩有不及格的学生的学号。 select distinct sno from sc where grade<60
2.2.2 确定范围(BETWEEN...AND,NOT BETWEEN...AND)
--查询年龄在20-23岁(包括20岁和23岁)之间的学生的姓名、系别和年龄 select sname,sdept,sage from student where sage between 20 and 23 或者 select sname,sdept,sage from student where sage >=20 and sage<=23 --查询年龄不在20-23岁之间的学生姓名、系别和年龄 select sname,sdept ,sage from student where sage not between 20 and 23
2.2.3 确定集合。如果想根据是定列表中值的集合来作为条件选择行,可以使用 IN 和 NOT IN 运算符
--查询信息系(IS)、数学系(MA)和计算机科学系(CS)学生的姓名和性别。 select sname,ssex from student where sdept in('IS','MA','CS') --查询既不是信息系、数学系,也不是计算机科学系的学生的姓名和性别。 select sname,ssex from studnet where sdept not in('IS','MA','CS')
2.2.4 判断是否为空(IS NULL, NOT IS NULL)
--查找没有成绩的学生学号和对应的课程号 注意:没有成绩和成绩为0是不一样的,空值不能跟任何其他值进行比较,所以成绩为空不能表示成grade=null,而必须用 is null,语句为:
select sno,cno from sc where grade is null
2.2.5 字符匹配。(LIKE 和 NOT LIKE ,like谓词格式为[not] like '匹配串',可以用=代替like)
(1)匹配串为固定字符串
--查询学号为200215121的学生的详细情况。 select * from student where sno like '08001' 等价于:select * from student where sno = '08001'
(2)匹配串为含通配符的字符串
【支持SQL Server的通配符: % 匹配零个或更多字符的任意字符串;
- 匹配单个字符;
[] 指定范围或几何中的任何单个字符
[^] 不属于指定范围或几何的任何单字符】
【SQL中常用的也就是%、-,我一般不用Access,至于支持Access的通配符,就由You自己收集了】
--查询所有姓刘学生的姓名、学号和性别。 select sname,sno,ssex from student where sname like '刘%' --查询姓"欧阳"且全名为三个汉字的学生的姓名。 select sname from student where sname like '欧阳__'
(3)使用换码字符将通配符转义为普通字符
--查询DB_Design课程的课程号和学分。 select cno,ccredit from course where cname like 'DB\_Design' escape '\‘ --查询以"DB_"开头,且倒数第3个字符为 i的课程的详细情况。 select * from course where cname like 'DB\_%i_ _' ESCAPE '\'
【ESCAPE '\' 表示“ \” 为换码字符】
2.2.6 逻辑运算符的使用。可以利用逻辑运算符(AND、OR、NOT)在WHERE子句中建立复合条件,
AND:一假即假,OR:一真即真,NOT取反
--查询计算机系年龄在20岁以下的学生姓名 select sname from student where sdept='CS' and sage<20
2.2.7 算术运算符及表达式的使用。(+、-、*、\)
--查询1987年后出生的学生的姓名和出生年份 select sname,(2012-sage) as 'birthdate' from student where (2012-sage)>1987
2.3 对查询结果排序
如果没有指定查询结果的显示顺序,DBMS将按其最方便的顺序(通常是元组在表中的先后顺序)输出查询结果,用户可用 ORDER BY 子句指定按照一个或多个属性列(排序字段)的升序(ASC)或降序(DESC)重新排列查询结果,其中ASC为缺省值。ASC:排序列为空值的元组最后显示,DESC:排序列为空值的元组最先显示
--查询选修了3号课程的学生的学号及其成绩,查询结果按分数降序排列 select sno,grade from sc where cno='3' order by grade DESC
--查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列 select * from student order by sdept,sage DESC
2.4 分组函数的使用。(也称聚集函数、集合函数)
计数:COUNT([ DISTINCT | ALL ] *)
COUNT([ DISTINCT | ALL ] <列名>)
计算总和:SUM([ DISTINCT | ALL ] <列名>)
计算平均值:AVG([ DISTINCT | ALL ] <列名>)
最大最小值:MAX([ DISTINCT | ALL ] <列名>)
MIN([ DISTINCT | ALL ] <列名>)
--查询选修了课程的学生人数 select count(distinct sno) from sc --计算1号课程的学生平均成绩 select avg(grade) from sc where cno='1' --查询学生200215012选修课程的总学分数 select sum(ccredit) from sc,course where sno='200215012' and sc.cno=course.cno
2.5 对查询结果分组。
GROUP BY子句: 细化聚集函数的作用对象:未对查询结果分组;聚集函数将作用于整个查询结果;对查询结果分组后,聚集函数将分别作用于每个组;作用对象是查询的中间结果表;按指定的一列或多列值分组,值相等的为一组。
--查询选修了3门以上课程的学生学号 select sno from sc group by sno having count(*)>3
续:HAVING短语与WHERE子句的区别:
作用对象不同:WHERE子句作用于基表或视图,从中选择满足条件的元组;HAVING短语作用于组,从中选择满足条件的组。
--查询所有成绩为优秀的学生学号 select sno from sc where sno not in(select sno from sc where grade is null) group by sno having min(grade)>=90
三、连接查询。
连接查询:同时涉及多个表的查询
连接条件或连接谓词:用来连接两个表的条件
一般格式:
[<表名1>.]<列名1> <比较运算符> [<表名2>.]<列名2>
[<表名1>.]<列名1> BETWEEN [<表名2>.]<列名2> AND [<表名2>.]<列名3>
连接字段:连接谓词中的列名称
连接条件中的各连接字段类型必须是可比的,但名字不必是相同的。
1、等值连接:连接运算符为=
--查询每个学生及其选修课程的情况 select student.*,sc.* from studnet,sc where student.sno = sc.sno
2、自然连接
--查询每个学生及其选修课程的情况 select student.sno,sname,ssex,sdept,cno,grade from student,sc where student.sno = sc.sno
3、自身连接:一个表与其自己进行连接。需要给表起别名以示区别;由于所有属性名都是同名属性,因此必须使用别名前缀
--查询每一门课的间接先修课(即先修课的先修课) select first.cno,second.cpno from course first,course second where first.cpno=second.cno
4、外连接(左外连接,右外连接、全外连接)。与普通连接的区别:普通连接操作只输出满足连接条件的元组;外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出。
--查询每个学生及其选修课程的情况 select student.sno,sname,ssex,sage,sdept,cno,grade from student left out join sc on(student.sno=sc.sno)
5、复合条件连接(在WHERE子句中含多个连接条件)
--查询选修2号课程且成绩在90分以上的所有学生 select student.sno,sname from student,sc where student.sno=sc.sno and sc.cno='2' and sc.grade>90 --查询每个学生的学号、姓名、选修的课程名及成绩 select student.sno,sname,cname,grade from student,sc,course where student.sno=sc.sno and sc.cno=course.cno
6、字符串连接查询
--查询所有成绩为优秀的学生姓名 select sname from student,sc where student.sno=sc.sno and student.sno not in(select sno from sc where grade is nulll)group by sname having min(grade)>=90
四:子查询
子查询(或嵌套查询):一个 SELECT-FROM-WHERE 语句称为一个查询块,将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询称为子查询或嵌套查询。
子查询的限制:不能使用ORDER BY子句
子查询求解方法:
(1)相关子查询:
子查询的查询条件不依赖于父查询;
由里向外、逐层处理,即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。
(2)相关子查询:子查询的查询条件依赖于父查询
首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表中,然后再取外层表的下一个元组,重复这一过程,直至外层表全部检查完为止。
1、带有IN的子查询
--查询与“刘晨”在同一个系学习的学生 【此查询为不相关查询】
此查询可分为两步:
(1)确定“刘晨”所在系名 select sdept from student where sname='刘晨' (2)查找所有在CS系学习的学生 select sno,sname,sdept from student where sdept='CS'
合起来即为:
select sno,sname,sdept from student where sdept in(select sdept from student where sname='刘晨')
也可用自身连接来做该题:
select s1.sno,s1.sname,s1.sdept from student s1,student s2 where s1.sdept=s2.sdept and s2.sname='刘晨'
--查询选修了课程名为“信息系统”的学生学号和姓名 select sno,sname from student where sno in(select sno from sc where cno in(select cno from course where cname='信息系统'))
也用连接查询实现:
select sno,sname from student,SC,course where student.sno=SC.sno and SC.cno=course.cno and course.cname='信息系统'
2、带有比较运算符的子查询。
当能确切知道内层查询返回单值时,可用比较运算符(>,<,=,>=,<=,!=或< >),与ANY或ALL谓词配合使用(下面会讲到ANY、SOME、ALL)。
--查询年龄大于所有学生平均年龄的学生的信息 此查询也可分为两步: (1)确定所有学生的平均年龄 select avg(sage) from student 【假设查询结果为18.8】 (2)查询年龄比该平均年龄(18.8)大的学生信息 select * from student where sage>=18.8
合起来即为
select * from student where sage>(select avg(sage) from student ) --找出每个学生超过他选修课程平均成绩的课程号 【此查询为相关子查询】 select sno,cno from SC x where grade>=(select avg(grade) from SC y where y.sno=x.sno)
3、带有ANY(SOME)或ALL谓词的子查询。ANY、SOME、ALL可以与各种比较运算符共同使用,特别指出的是 !=(或<>)ANY 是不等于子查询结果中的某个值,
!=(或<>)ALL 不等于子查询结果中的任何一个值。
--查询其他系中比计算机科学某一学生年龄小的学生姓名和年龄 方法一:用any谓词 select sname,sage from student where sage<any(select sage from student where sdept='CS') and sdept<>'CS' 方法二:用聚集函数 select sname,sage from student where sage<(select max(sage) from student where sdept='CS') and sdept <> 'CS'
--查询其他系中比计算机科学系所有学生年龄都小的学生姓名及年龄 方法一:用all谓词 select sname,sage from student where sage < all(select sage from student where sdept='CS') and sdept <> 'CS' 方法二:用聚集函数 select sname,sage from student where sage < (select min(sage) from student where sdept='CS') and sdept <>'CS'
4、带有EXISTS谓词的子查询
(1) EXISTS谓词
存在量词,带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true”或逻辑假值“false”。若内层查询结果非空,则外层的WHERE子句返回真值;若内层查询结果为空,则外层的WHERE子句返回假值;由EXISTS引出的子查询,其目标列表达式通常都用* ,因为带EXISTS的子查询只返回真值或假值,给出列名无实际意义。
(2) NOT EXISTS谓词
若内层查询结果非空,则外层的WHERE子句返回假值;若内层查询结果为空,则外层的WHERE子句返回真值。
--查询所有选修了1号课程的学生姓名 方法一:用EXISTS查询 select sname from student where exists(select * from SC where sno=student.sno and cno='1') 方法二:用连接运算 select sname from student,SC where student.sno=SC.sno and SC.cno='1'
附:不同形式的查询间的替换
一些带 EXISTS 或 NOT EXISTS 谓词的子查询不能被其他形式的子查询等价替换,所有带 IN谓词、比较运算符、ANY 和 ALL 谓词的子查询都能用带EXISTS谓词的子查询等价替换。
--查询至少选修了学生08002选修的全部课程的学生号码 【思路:查询学号为x的学生,对所有的课程y,只要08002学生选修了课程y,则x也选修了y。变换后语义:不存在这样的课程y,学生08002选修了y,而学生x没有选。】 select distinct sno from SC SCX where not exists(select * from SC SCY where SCY.sno='08002' and not exists(select * from SC SCZ where SCZ.sno=SCX.sno and SCZ.sno=SCY.cno))
5、BETWEEN、LIKE 引导的子查询(只能引导单一行子查询,用的较少)
--查询年龄处于刘晨和刘立年龄之间的学生信息 select * from student where sage between(selecet sage from student where sname='刘晨') and (select sage from student where sname='刘立') 【上述在Access、Sql中都可以正常执行,但在Sql中用between...and时 between 后面只能跟下限值,and 后跟上限值】
五:集合查询
种类:并操作UNION、交操作INTERSECT、差操作EXCEPT。
要求:参加集合操作的各查询结果的列数必须相同;对应项的数据类型也必须相同。
语句:
--查询计算机科学系的学生及年龄不大于19岁的学生 方法一:select * from student where sdept='CS' union select * from student where sage<=19 方法二:select distinct * from student where student where sdept='CS' or sage<=19
--查询选修课程1的学生集合与选修课程2的学生集合的交集 select sno from SC where cno='1' intersect select sno from SC where cno='2' 实际上是查询既选修了课程1又选修了课程2的学生 select sno from SC where cno='1' and sno in(select sno from SC where cno='2')
--后记:加油,@_@