数据库是以select语句为基本对数据库进行信息查询的,这里面有很多使用方式,下面对此做一一总结。数据库查询语句的一般格式为:
select [all | distinct]<目标列表达式>[,<目标列表达式>]---
from <表名或视图名>[,<表名或视图名>]---
[where <条件表达式>]
[group by <列名1>[having <条件表达式>]]
[order by <列名2>[ASC|DESC]];
其中,如果有group by子句,则将结果按<列名1>的值进行分组,该属性列值相等的元祖为一个组。通常会在每组中使用聚集函数,如果group by子句中带有having短语,则只有在满足指定条件的组才给输出来。
如果有order by子句,则结果按<列名2>的值升序或降序排序。例如有表Student,其值如下:
mysql> select * from Student;
+--------+--------+------+------+-------+
| Sno | Sname | Ssex | Sage | Sdept |
+--------+--------+------+------+-------+
| sa1211 | Lily | F | 19 | MA |
| sa1212 | ello | F | 19 | CS |
| sa1213 | Hello | M | 20 | CS |
| sa1214 | Shely | F | 19 | IS |
| sa1215 | Shelly | F | 19 | CS |
| sa1216 | 赵三 | F | 19 | CS |
| sa1217 | 赵四 | F | 19 | CS |
| sa1218 | 张良 | F | 19 | CS |
| sa1219 | 张子房 | F | 19 | CS |
+--------+--------+------+------+-------+
1、查询经过计算的值,例如查询全体学生的姓名以及其出生年份,并用小写字母表示所在院系:
mysql> select Sname,"year of birth:",2017-Sage,lower(Sdept) from Student;
+--------+----------------+-----------+--------------+
| Sname | year of birth: | 2017-Sage | lower(Sdept) |
+--------+----------------+-----------+--------------+
| Lily | year of birth: | 1998 | ma |
| ello | year of birth: | 1998 | cs |
| Hello | year of birth: | 1997 | cs |
| Shely | year of birth: | 1998 | is |
| Shelly | year of birth: | 1998 | cs |
| 赵三 | year of birth: | 1998 | cs |
| 赵四 | year of birth: | 1998 | cs |
| 张良 | year of birth: | 1998 | cs |
| 张子房 | year of birth: | 1998 | cs |
+--------+----------------+-----------+--------------+
2、选择表中若干元组
2.1 取消重复的行,例如查询出所有的院系,去掉重复的值,如下:
mysql> select distinct Sdept from Student;
+-------+
| Sdept |
+-------+
| MA |
| CS |
| IS |
+-------+
2.2 查询满足条件的元组,可以通过where子句进行实现,常用的查询条件如下:
查询条件 | 谓词 |
比较 | =,>,<,>=,<=,!=,!>,!<;NOT+上述比较运算符 |
确定范围 | BETWEEN AND,NOT BETWEEN AND |
确定集合 | IN,NOT IN |
字符匹配 | LIKE,NOT LIKE |
空值 | IS FULL,IS NOT FULL |
多重条件 | AND,OR,NOT |
例如查询计算机科学系(CS),数学系(MA)学生的姓名和性别。
mysql> select Sname,Ssex from Student where Sdept in ('CS','MA');
+--------+------+
| Sname | Ssex |
+--------+------+
| Lily | F |
| ello | F |
| Hello | M |
| Shelly | F |
| 赵三 | F |
| 赵四 | F |
| 张良 | F |
| 张子房 | F |
+--------+------+
与IN相对的谓词是NOT IN表示要查找的属性不在指定属性集合的范围内。
字符串匹配查询,查找所有不姓“赵”的学生:
mysql> select * from Student where Sname not like "赵%";
+--------+--------+------+------+-------+
| Sno | Sname | Ssex | Sage | Sdept |
+--------+--------+------+------+-------+
| sa1211 | Lily | F | 19 | MA |
| sa1212 | ello | F | 19 | CS |
| sa1213 | Hello | M | 20 | CS |
| sa1214 | Shely | F | 19 | IS |
| sa1215 | Shelly | F | 19 | CS |
| sa1218 | 张良 | F | 19 | CS |
| sa1219 | 张子房 | F | 19 | CS |
+--------+--------+------+------+-------+
2.3 聚集函数,sql有很多聚集函数,主要有:
count([distinct|all]*) 统计元组个数
count([distinct |all <列名>]) 统计一列中值的个数
SUM([distinct |all <列名>])计算一列值的总和(需是数值类型)
AVG([distinct |all <列名>]) 计算一列值的平均数(需是数值类型)
MAX([distinct |all <列名>])计算一列值的最大数
MIN([distinct |all <列名>])计算一列值的最小数
如果指定distinct短语,表示计算时需要取消指定列中的重复值。如果不指定distinct或指定All短语(all可缺省),则表示不取消重复值。
例如,计算每一个院系的学生个数,如下:
mysql> select count(*),Sdept from Student group by(Sdept);
+----------+-------+
| count(*) | Sdept |
+----------+-------+
| 7 | CS |
| 1 | IS |
| 1 | MA |
+----------+-------+
选出人数大于3的院系,以及该院系的人数:
mysql> select count(*),Sdept from Student group by(Sdept) having count(*)>3;
+----------+-------+
| count(*) | Sdept |
+----------+-------+
| 7 | CS |
+----------+-------+
这里先用group by进行分组,然后再用count对每一组计数。having短语给出了选择组的条件,只有满足条件的组才会被选出。
3、连接查询
3.1 等值连接和非等值连接查询
根据上表中的“比较”和“范围”条件,当连接运算符为=时,表示为等值连接,使用其他运算符为非等值连接。例如,学生表student,选课表sc,这两个表的连接是通过公共属性Sno实现的。利用该属性实现的连接查询如下:
mysql> select student.*,sc.*
-> from student,sc
-> where student.Sno=sc.Sno;
+--------+-------+------+------+-------+--------+-----+-------+
| Sno | Sname | Ssex | Sage | Sdept | Sno | Cno | Grade |
+--------+-------+------+------+-------+--------+-----+-------+
| sa1211 | Lily | F | 19 | MA | sa1211 | 1 | 89 |
| sa1211 | Lily | F | 19 | MA | sa1211 | 2 | 90 |
| sa1211 | Lily | F | 19 | MA | sa1211 | 3 | 90 |
| sa1212 | ello | F | 19 | CS | sa1212 | 1 | 78 |
| sa1212 | ello | F | 19 | CS | sa1212 | 3 | 90 |
+--------+-------+------+------+-------+--------+-----+-------+
该语句的查询过程是这样的,首先在表student中找到第一个元组,然后从头开始扫描SC表,逐一查找与student表第一个元组的Sno相等的SC元组,找到后就将student中的第一个元组与该元组拼接起来,形成结果表中的一个元组。如果SC表上的Sno建立索引的话,就不用每次扫描SC表了。
3.2 自身连接
连接操作不仅可以在两个表之间进行,还可以与自身进行连接,如下:
mysql> select * from course;
+-----+------------------+------+---------+
| Cno | Cname | Cpno | Ccredit |
+-----+------------------+------+---------+
| 1 | database | 5 | 3 |
| 2 | math | NULL | 2 |
| 3 | INFO SYS | 1 | 2 |
| 4 | operating system | 6 | 2 |
| 5 | data structure | 7 | 4 |
| 6 | data process | NULL | 4 |
| 7 | PASCAL | 6 | 4 |
+-----+------------------+------+---------+
表Course中的Cpno表示的是这门课程的先行课程,查询一门课程的间接先修课如下:
mysql> select first.Cno,second.Cpno
-> from course first,course second
-> where first.Cpno=second.Cno;
+-----+------+
| Cno | Cpno |
+-----+------+
| 3 | 5 |
| 1 | 7 |
| 4 | NULL |
| 7 | NULL |
| 5 | 6 |
+-----+------+
通过Coruse表的内容可知,3的先行课是1,而1的先行课是5,所以3的间接先行课程是5,其它分析一样。
3.3 外连接
先看一个例子:
mysql> select student.Sno,Sname,Ssex,Sdept,Cno,Grade
-> from student,sc where student.Sno=sc.Sno;//这里用的是“等值连接”
+--------+-------+------+-------+-----+-------+
| Sno | Sname | Ssex | Sdept | Cno | Grade |
+--------+-------+------+-------+-----+-------+
| sa1211 | Lily | F | MA | 1 | 89 |
| sa1211 | Lily | F | MA | 2 | 90 |
| sa1211 | Lily | F | MA | 3 | 90 |
| sa1212 | ello | F | CS | 1 | 78 |
| sa1212 | ello | F | CS | 3 | 90 |
+--------+-------+------+-------+-----+-------+
mysql> select student.Sno,Sname,Ssex,Sdept,Cno,Grade
-> from student left join sc on (student.Sno=sc.Sno);//这里用的是“外连接”中的“左外连接”
+--------+--------+------+-------+------+-------+
| Sno | Sname | Ssex | Sdept | Cno | Grade |
+--------+--------+------+-------+------+-------+
| sa1211 | Lily | F | MA | 1 | 89 |
| sa1211 | Lily | F | MA | 2 | 90 |
| sa1211 | Lily | F | MA | 3 | 90 |
| sa1212 | ello | F | CS | 1 | 78 |
| sa1212 | ello | F | CS | 3 | 90 |
| sa1213 | Hello | M | CS | NULL | NULL |
| sa1214 | Shely | F | IS | NULL | NULL |
| sa1215 | Shelly | F | CS | NULL | NULL |
| sa1216 | 赵三 | F | CS | NULL | NULL |
| sa1217 | 赵四 | F | CS | NULL | NULL |
| sa1218 | 张良 | F | CS | NULL | NULL |
| sa1219 | 张子房 | F | CS | NULL | NULL |
+--------+--------+------+-------+------+-------+
有时候想以student表为主体选出每个学生的基本情况和选课情况,如果用等值连接的话,则那些还未选课的同学的信息将不会展示出来,这时候“外连接”的作用突显出来了,我们可以用“外连接”实现该功能,外连接分为左外连接和右外连接,假设有两张表A和B,如果A左外连接B,则显示的结果是以A为主体,A的信息将会完全展示,而B中没有的信息将会显示为NULL;右连接与之相对应,如果A右外连接B,则将会完全显示B的信息。
3.4、复合条件连接
如果一个查询语句中,where语句中有多个连接条件,则称为“复合条件连接”。例如,查询选修2号课程且成绩在90分以上的所有学生:
select student.Sno,Sname
from student,sc
where student.Sno=sc.Sno and sc.Cno='2' and sc.grade>90;
4 嵌套查询
如果将一个查询块嵌套在另一个查询块的where或having短语的条件中的查询称之为“嵌套查询”,嵌套查询有以下几种情况:
4.1 带有in的嵌套查询
嵌套查询中,子查询的结果常是一个集合,为了完成嵌套查询,常常先进行分步查询,例如,查询与“张子房”在同一个系学习的学生,可以分为以下步骤:
第一步:查询“张子房”同学所在的系别,select Sdept from student where Sname="张子房";//结果为CS
第二步:查询所有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="张子房");
这里,子查询的查询条件不依赖于父查询,称之为“不相关子查询”。
4.2 带有比较运算符的子查询
当子查询返回的是单值时,可以用>,<,>=,<=,!=或<>等比较运算符进行相关条件的查询。例如上句中,“张子房”只能在一个系别中,所以查询语句还可以是:
select Sno,Sname,Sdept
from student where Sdept = ( select Sdept from student where Sname="张子房");
再比如,查询每个学生超过他选修课程平均成绩的课程号:
select Sno,Cno from SC x where grade >=(
select AVG(grade) from SC y where y.Sno=x.Sno);
这里,内查询是一个查询所有选修课程平均成绩的,至于是哪一个学生的平均成绩是要看参数x.Sno的值,而该值是和父查询相关的,所以,这类查询称之为相关子查询。
4.3 带有ANY(SOME)或ALL谓词的子查询
子查询返回单值时可以用比较运算符,但返回多值是要用ANY(有的系统用SOME)或ALL修饰。其语义如下:
> ANY 大于子查询中结果中的某个值
> ALL 大于子查询中结果中的所有值
...
!=(或<>)ANY 不等于子查询中结果中的某个值
!=(或<>)ALL 不等于子查询中结果中的所有值
例如:查询其他系中比计算机系中所有学生年龄都小的学生姓名和年龄:
select Sname,Sage from student where Sage < ALL( select Sage from student where Sdept="CS") and Sdept<>"CS";
4.4 带有EXISTS谓词的子查询
带有exists谓词的子查询不返回任何数据,只产生逻辑真“true”或逻辑假“false”。例如,查询所有选修了1号课程的学生姓名:
select Sname from student where exists(select * from SC where Sno=student.Sno and Cno="1");
反之,查询没有选修1号课程的学生姓名:
select Sname from student where not exists(select * from SC where Sno=student.Sno and Cno="1");
再比如,查询至少选修了学生200215选修的全部课程的学生号,其语义是这样的:不存在这样的课程y,学生200215选修了y,而学生x没有选。sql语句如下:
select distinct Sno from SC x where not exists(
select * from SC y where y.Sno='200215' and not exists(
select * from SC z where z.Sno=x.Sno and z.Cno=y.Cno));//表示x与y选修相同课程的课程,加上前面的not exists,表示x不与y选修相同课程的课程;再加上最外层的not exists,表示不存在这样的课程,y选修了,而x不与y选修相同的课程,双重否定是肯定,表示,y选修的课程,x都有选择。
5 集合查询
select 语句的查询结果是元组的集合,所以,多个select查询可以进行集合操作,集合操作包括union(并)、intersect(交)、except(差)操作。这里,参与集合操作的各查询结果的列数必须相同,而且对应项的数据类型必须相同。
5.1 union操作,表示并操作,例如,查询计算机系的学生以及年龄不大于19的学生。代码如下:
select * from student where Sdept="CS"
union
select * from student where Sage<=19;
5.2 intersect操作,表示交操作,例如查询既选修了课程1又选修了课程2的学生。代码如下:
select Sno from SC where Cno='1'
intersect
select Sno from SC where Cno='2';
5.3 except操作,表示差操作,例如查询计算机系的学生与年龄不大于19岁的学生的差集:
select * from student where Sdept='CS'
except
select * from student where Sage<=19;
其实,以上语句的效果就是查询计算机系中,年龄大于19岁的学生:
select * from student where Sdept='CS' and Sage>19;
以上是数据查询的总结...