关系数据库标准语言SQL
Posted zhouyeqin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关系数据库标准语言SQL相关的知识,希望对你有一定的参考价值。
篇幅过长,恐惧者慎入!!!基础知识,大神请绕道!!!
本节要点:
- l SQL概述
- l 学生-课程关系
- l 数据定义
- 基本表的定义、删除与修改
- 索引的建立与删除
- l 查询
- 单表查询
- 连接查询
- 嵌套查询
- 集合查询
- l 数据更新
- 插入数据
- 修改数据
- 删除数据
- l 视图
- 定义视图
- 查询视图
- 更新视图
- 视图的作用
SQL(Structured Query Language),即结构化查询语言,是关系数据库的标准语言,SQL是一个通用的、功能极强的关系数据库语言。当前,几乎所有的关系数据库管理系统软件都支持SQL。本节将主要介绍SQL。
1 SQL概述
SQL是在1974年由Boyce和Chamberlin提出的,并在IBM公司研制的关系数据库管理系统原型System R上实现。SQL之所以能够为用户和业界所接受,并成为国际标准,是因为它是一个综合的、功能极强同时又简介易学的语言。SQL集数据查询(Data Query)、数据操纵(Data Manipulation)、数据定义(Data Definition)和数据控制(Data Control)功能于一体。
SQL的特点:
- l 综合统一
- l 高度非过程化
- l 面向集合的操作方式
- l 以同一种语法结构提供两种使用方法(交互式, 嵌入式)
- l 语言简洁,易学易用
注:SQL完成核心功能只用了下面9个动词:
2 学生-课程关系
接下来知识的学习需要用到学生-课程的关系作为例子来讲解,所以先给出3个表的关系:
- l 学生表:Student(Sno,Sname,Ssex,Sage,Sdept)
- l 课程表:Course(Cno,Cname,Cpno,Ccredit)
- l 学生选课表:SC(Sno,Cno,Grade)
注:加下划线的是关系中的主码。
各个表中的数据示例如下(表的具体定义后续会讲到,先看看表的结构和信息):
Student
学号Sno |
姓名Sname |
性别Ssex |
年龄Sage |
所在系Sdept |
200215121 |
李勇 |
男 |
20 |
CS |
200215122 |
刘晨 |
女 |
19 |
CS |
200215123 |
王敏 |
女 |
18 |
MA |
200215125 |
张立 |
男 |
19 |
IS |
Course
课程号Cno |
课程名Cname |
先行课Cpno |
学分Ccredit |
1 |
数据库 |
5 |
4 |
2 |
数学 |
|
2 |
3 |
信息系统 |
1 |
4 |
4 |
操作系统 |
6 |
3 |
5 |
数据结构 |
7 |
4 |
6 |
数据处理 |
|
2 |
7 |
PASCAL语言 |
6 |
4 |
SC
学号Sno |
课程号Cno |
成绩Grade |
200215121 |
1 |
92 |
200215121 |
2 |
85 |
200215121 |
3 |
88 |
200215122 |
2 |
90 |
200215122 |
3 |
80 |
3 数据定义
关系数据库系统支持三级模式结构,其模式、外模式和内模式中的基本对象由表、视图和索引,因此SQL的数据定义功能包括表定义、视图和索引的定义,如下表是SQL的数据定义语句总结:
3.1 基本表的定义、删除与修改
1) 定义基本表
语法:
CREATE TABLE <表名>
(<列名> <数据类型>[ <列级完整性约束条件> ]
[,<列名> <数据类型>[ <列级完整性约束>] ] …
[,<表级完整性约束> ]
);
<表名>:所要定义的基本表的名字
<列名>:组成该表的各个属性(列)
<列级完整性约束条件>:涉及相应属性列的完整性约束条件
<表级完整性约束条件>:涉及一个或多个属性列的完整性约束条件
示例:
- 建立学生表Student:
CREATE TABLE Student
(Sno CHAR(5) PRIMARY KEY, /* PRIMARY KEY是完整性约束,以后讲到*/
Sname CHAR(20) NOT NULL,
Ssex CHAR(1) ,
Sage INT,
Sdept CHAR(15));
- 建立一个“课程”表Course:
CREATE TABLE Course
(Cno CHAR(5) PRIMARY KEY,
Cname CHAR(20) NOT NULL,
Cpno CHAR(5) ,
Credit INT,
FOREIGN KEY Cpno REFERENCES Course(Cno));
注:说明参照表和被参照表可以是同一个。
- 建立一个“学生选课”表SC,它由学号Sno、课程号Cno,修课成绩Grade组成,其中(Sno, Cno)为主码:
CREATE TABLE SC(
Sno CHAR(5) ,
Cno CHAR(3) ,
Grade INT,
Primary key (Sno, Cno),
FOREIGN KEY (Sno) REFERENCES Student(Sno)
FOREIGN KEY (Cno) REFERENCES Course(Cno));
2) 数据类型
关系模型中一个很重要的概念是域,每一个属性来自一个域,它的取值必须是域中的值。在SQL中域的概念用数据类型来实现,在定义表的各个属性时需要指明其数据类型及长度。SQL提供了一些主要数据类型如下(不同的RDBMS中支持的数据类型不尽相同):
数据类型 |
含义 |
CHAR(n) |
长度为n的定长字符串 |
VARCHAR(n) |
最大长度为n的变长字符串 |
INT |
长整数(也可以写成INTEGER) |
SMALLINT |
短整数 |
NUMBERIC(p,d) |
定点数,由p为数字(不包括符号、小数点)组成,小数后面有d位数字 |
REAL |
取决于机器精度的浮点数 |
Double Percision |
取决于机器精度的双精度浮点数 |
FLOAT(n) |
浮点数,精度至少为n位数字 |
DATE |
日期,包含年月日,格式为YYYY-MM-DD |
TIME |
时间,包含一日的时分秒,格式为HH:MM:SS |
注:VARCHAR、NUMBERIC和DATE较常用。
3) 删除基本表
语法:
DROP TABLE <表名> [RESTRICT|CASCADE];
RESTRICT:该表删除是有限制的,待删除的表不能被其他表的约束所引用,否则不能删除;
CASCADE:删除表的同时删除其他约束对象。
一般默认是RESTRICT。
示例:(慎用,一旦删除不可恢复)
删除Student表
DROP TABLE Student RESTRICT;
4) 修改基本表
语法:
ALTER TABLE <表名>
[ ADD <新列名> <数据类型> [ 完整性约束 ] ]
[ DROP <原列名>|<完整性约束名> ]
[ALTER COLUMN <原列名> <数据类型> ];
- <表名>:要修改的基本表
- ADD子句:增加新列和新的完整性约束条件
- DROP子句:删除指定的列或完整性约束
- ALTER COLUMN子句:用于修改指定列的数据类型
示例:
向Student表增加“入学时间”列,其数据类型为日期型:
ALTER TABLE Student ADD Scome DATE;
将年龄的数据类型由字符型(假设原来的数据类型是字符型)改为整数:
ALTER TABLE Student ALTER COLUMN Sage INT;
删除列属性:
ALTER TABLE Student Drop Scome;
3.2 索引的建立与删除
假设你负责一本学生记录表(2万学生要近千页). 经常有人来要求按学生名查询某某学生信息。你如何查才能提高查询速度?我们知道一般在文档操作的时候就有建立学生名目录(按拼音排序)。同样,运用到数据库上,可以在一列或者多列上建立索引,根据索引去查询。相比较对整个表进行查询,索引查询只是选取了一列或者几列,查询的范围小,查询时数据占用的内存小。
1) 建立索引
建立索引是加快查询速度的有效手段
语法:
CREATE INDEX <索引名>
ON <表名>(<列名 [,<列名> ]…);
示例:
为Student的sname列建立索引:
CREATE INDEX StuName ON Student(Sname);
2) 删除索引
语法:
DROP INDEX <索引名>;
示例:删除Student表的Stusname索引。
DROP INDEX Stusname;
4 查询
数据库查询时数据库的核心操作。SQL提供了SELECT语句进行数据库的操作,其一般格式如下:
SELECT [ALL|DISTINCT] <目标列表达式> [,<目标列表达式>] …
FROM <表或视图名>[,<表或视图名> ] …
[ WHERE <条件表达式> ]
[ GROUP BY <列名1>
[ HAVING <条件表达式> ] ]
[ ORDER BY <列名2> [ ASC|DESC ] ];
- SELECT子句:指定要显示的属性列
- FROM子句:指定查询对象(基本表或视图)
- WHERE子句:指定查询条件
- GROUP BY子句:对查询结果按指定列的值分组,该属性列值相等的元组为一个组。通常会在每组中作用集函数。
- HAVING短语:筛选出只有满足指定条件的组
- ORDER BY子句:对查询结果表按指定列值的升序或降序排序
4.1 单表查询
单表查询表示查询仅涉及一个表,是一种最简单的查询操作:
一、选择表中的若干列
二、选择表中的若干元组
三、对查询结果排序
四、使用集函数
五、对查询结果分组
1) 查询指定列
示例:查询全体学生的学号与姓名。
SELECT Sno,Sname FROM Student;
示例: 查询全体学生的姓名、学号、所在系。
SELECT Sname,Sno,Sdept FROM Student;
2) 查询全部列
示例:查询全体学生的详细记录。
SELECT Sno,Sname,Ssex,Sage,Sdept FROM Student;
或
SELECT * FROM Student;
3) 查询经过计算的值
SELECT子句的<目标列表达式>不仅可以是表中的属性列,也可以是表达式。
示例:查全体学生的姓名及其出生年份。
SELECT Sname,2012-SageFROM Student;
示例:查询全体学生的姓名、出生年份和所有系,要求用小写字母表示所有系名。
SELECT Sname,\'Year of Birth: \',2012 Sage, ISLOWER(Sdept) FROM Student;
4) 使用列别名(可选)改变查询结果的列标题
示例:SELECT Sname NAME,\'Year of Birth: \' BIRTH,2012-Sage BIRTHDAY,ISLOWER(Sdept) DEPARTMENT FROM Student;
输出结果:
NAME BIRTH BIRTHDAY DEPARTMENT
------- -------- ------- ------- --------
李勇 Year of Birth: 1986 cs
刘晨 Year of Birth: 1987 is
王名 Year of Birth: 1988 ma
张立 Year of Birth: 1987 is
5) 消除取值重复的行
- ALL查询满足条件的元组
SELECT ALL Sno FROM SC;
等价于
SELECT Sno FROM SC;
结果:Sno
-------
95001
95001
95001
95002
95002
- DISTINCT消除取值重复的行
SELECT DISTINCT Sno FROM SC;
结果: Sno
-------
95001
95002
注意 DISTINCT短语的作用范围是所有目标列
例:查询选修课程的各种成绩
错误的写法:
SELECT DISTINCT Cno,DISTINCT Grade FROM SC;
正确的写法
SELECT DISTINCT Cno,Grade FROM SC;
6) 查询满足条件的元组
查询满足指定条件的元组可以通过WHERE字句实现。WHERE字句常用的查询条件如下:
查询条件 |
谓词 |
比较 |
=,>,<,>=,<=,!=,<>,!>,!<;NOT+上述比较运算符 |
确定范围 |
BETWEEN AND,NOT BETWEEN AND |
确定集合 |
IN,NOT IN |
字符匹配 |
LIKE,NOT LIKE |
空值 |
IS NULL,IS NOT NULL |
多重条件(逻辑运算) |
AND,OR,NOT |
- 比较大小
在WHERE子句的<比较条件>中使用比较运算符=,>,<,>=,<=,!= 或 <>,!>,!<,逻辑运算符NOT + 比较运算符
示例: 查询所有年龄在20岁以下的学生姓名及其年龄。
SELECT Sname,Sage
FROM Student
WHERE Sage < 20;
或
SELECT Sname,Sage
FROM Student
WHERE NOT Sage >= 20;
- 确定范围
使用谓词 BETWEEN … AND …
NOT BETWEEN … AND …
示例:查询年龄在20~23岁(包括20岁和23岁)之间的学生的姓名、系别和年龄。
SELECT Sname,Sdept,Sage
FROM Student
WHERE Sage BETWEEN 20 AND 23;
示例:查询年龄不在20~23岁之间的学生姓名、系别和年龄。
SELECT Sname,Sdept,Sage
FROM Student
WHERE Sage NOT BETWEEN 20 AND 23;
- 确定集合
使用谓词IN (值表)、NOT IN (值表)。值表:用逗号分隔的一组取值
示例:
查询信息系(IS)、数学系(MA)和计算机科学系(CS)学生的姓名和性别。
SELECT Sname,Ssex
FROM Student
WHERE Sdept IN ( \'IS\',\'MA\',\'CS\' );
查询既不是信息系、数学系,也不是计算机科学系的学生的姓名和性别。
SELECT Sname,Ssex
FROM Student
WHERE Sdept NOT IN ( \'IS\',\'MA\',\'CS\' );
- 字符串匹配
谓词like可以用来进行字符串的匹配。其一般语法格式如下:
[NOT] LIKE ‘<匹配串>’ [ESCAPE ‘ <换码字符>’]
其中<匹配串>用来指定匹配模板,可以是一个完整的字符串,也可以含有通配符%和_。其中:
-
- % (百分号) 代表任意长度(长度可以为0)的字符串。例:a%b表示以a开头,以b结尾的任意长度的字符串。如acb,addgb,ab 等都满足该匹配串
- _ (下横线) 代表任意单个字符。例:a_b表示以a开头,以b结尾的长度为3的任意字符串。如acb,afb等都满足该匹配串
a 匹配模板为固定字符串
示例:查询学号为95001的学生的详细情况。
SELECT *
FROM Student
WHERE Sno LIKE \'95001\';
等价于
SELECT *
FROM Student
WHERE Sno = \'95001\';
b 匹配模板为含通配符的字符串
示例: 查询所有姓刘学生的姓名、学号和性别。
SELECT Sname,Sno,Ssex
FROM Student
WHERE Sname LIKE ‘刘%’;
示例: 查询姓"欧阳"且全名为三个汉字的学生的姓名。
SELECT Sname
FROM Student
WHERE Sname LIKE \'欧阳__\';
示例: 查询名字中第2个字为"阳"字的学生的姓名和学号。
SELECT Sname,Sno
FROM Student
WHERE Sname LIKE \'__阳%\';
示例: 查询所有不姓刘的学生姓名。
SELECT Sname,Sno,Ssex
FROM Student
WHERE Sname NOT LIKE \'刘%\';
ESCAPE 短语:当用户要查询的字符串本身就含有 % 或 _ 时,要使用ESCAPE \'<换码字符>\' 短语对通配符进行转义。
使用换码字符将通配符转义为普通字符
示例:查询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 \' \\ \';
- 涉及空值的查询
使用谓词 IS NULL 或 IS NOT NULL。“IS NULL” 不能用 “= NULL” 代替。
示例:某些学生选修课程后没有参加考试,所以有选课记录,但没有考试成绩。查询缺少成绩的学生的学号和相应的课程号。
SELECT Sno,Cno
FROM SC
WHERE Grade IS NULL;
示例:查所有有成绩的学生学号和课程号。
SELECT Sno,Cno
FROM SC
WHERE Grade IS NOT NULL;
- 多重条件查询
用逻辑运算符AND和 OR来联结多个查询条件。AND的优先级高于OR,可以用括号改变优先级。
可用来实现多种其他谓词[NOT] IN和 [NOT] BETWEEN … AND …
示例:查询计算机系年龄在20岁以下的学生姓名。
SELECT Sname
FROM Student
WHERE Sdept= \'CS\' AND Sage<20;
示例:查询信息系(IS)、数学系(MA)和计算机科学系(CS)学生的姓名和性别。
SELECT Sname,Ssex
FROM Student
WHERE Sdept IN ( \'IS\',\'MA\',\'CS\' )
等价于:
SELECT Sname,Ssex
FROM Student
WHERE Sdept= \' IS \' OR Sdept= \' MA\' OR Sdept= \' CS
示例:查询年龄在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;
7) 对查询结果排序
排序使用ORDER BY子句,可以按一个或多个属性列排序,升序关键字是ASC,降序关键字是DESC,缺省值为升序。当排序列含空值时,ASC:排序列为空值的元组最后显示;DESC:排序列为空值的元组最先显示 。
示例:查询选修了3号课程的学生的学号及其成绩,查询结果按分数降序排列。
SELECT Sno,Grade
FROM SC
WHERE Cno= \' 3 \'
ORDER BY Grade DESC;
示例:查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列。
SELECT *
FROM Student
ORDER BY Sdept,Sage DESC;
8) 使用集函数
1行计数
(1)COUNT([DISTINCT|ALL] *):对每行计数;DISTINCT短语表示在计算时要取消指定列中的重复值;ALL短语表示不取消重复值,ALL为缺省值
(2)COUNT([DISTINCT|ALL] <列名>):对<列名>非空的行计数
示例: 查询学生总人数。
SELECT COUNT(*)
FROM Student;
示例: 查询选修了课程的学生人数。
SELECT COUNT(DISTINCT Sno)
FROM SC;
注:对Sno非空的行,排除重复Sno计数。以避免重复计算学生人数
有什么区别?
SELECT COUNT(*) FROM SC;
SELECT COUNT(Grade) FROM SC;
有什么区别?
SELECT COUNT(SNO) FROM SC;
SELECT COUNT(DISTINCT SNO) FROM SC;
2.计算总和(对非空列)
SUM([DISTINCT|ALL] <列名>)
3.计算平均值(对非空列)
AVG([DISTINCT|ALL] <列名>)
示例:计算1号课程的学生平均成绩。
SELECT AVG(Grade)
FROM SC
WHERE Cno= \' 1 \';
4.求最大值(对非空列)
MAX([DISTINCT|ALL] <列名>)
示例:查询选修1号课程的学生最高分数。
SELECT MAX(Grade)
FROM SC
WHER Cno= \' 1 \';
5.求最小值(对非空列)
MIN([DISTINCT|ALL] <列名>)
9) 对查询结果分组
使用GROUP BY子句分组,用来细化集函数的作用对象
- 未对查询结果分组,集函数将作用于整个查询结果
- 对查询结果分组后,集函数将分别作用于每个组
示例:求各个课程号及相应的选课人数。
SELECT Cno,COUNT(Sno)
FROM SC
GROUP BY Cno;
易犯错误:
SELECT Sno, Cno, COUNT(Sno)
FROM SC
GROUP BY Cno;
注意:使用GROUP BY子句后,SELECT子句的列名列表中只能出现分组属性和集函数
用多个列分组
示例:查询每个系男女生人数。
SELECT Sdept, Ssex, COUNT(*)
FROM Student
GROUP BY Sdept, Ssex;
使用HAVING短语筛选最终输出结果(having都是跟随group by对分组信息进行筛选):
示例:查询选修了3门以上课程的学生学号。
SELECT Sno
FROM SC
GROUP BY Sno
HAVING COUNT(*) >=3;
示例:查询有3门以上课程是90分以上的学生的学号及(90分以上的)课程数
SELECT Sno, COUNT(*)
FROM SC
WHERE Grade>=90
GROUP BY Sno
HAVING COUNT(*)>=3;
只有满足HAVING短语指定条件的组才输出,HAVING短语与WHERE子句的区别:作用对象不同:WHERE子句作用于基表或视图,从中选择满足条件的元组;HAVING短语作用于组,从中选择满足条件的组。
4.2 连接查询
前面的查询都是针对一个表进行的。若一个查询同时涉及两个以上的表,则称之为连接查询。连接查询是关系数据库中最主要的查询,包括等值连接查询、自然连接查询、非等值连接查询、自身连接查询、外连接查询和复合条件连接查询等。
连接查询的WHERE字句中用来连接两个表的条件称为连接条件或连接谓词,其一般格式为:
[<表名1>.] <列名1> <比较运算符> [<表名2>.] <列名2>
其中比较运算符主要有:=、>、<、>=、<=、!=(或<>)等。
此外连接谓词还可以使用下面形式:
[<表名1>.] <列名1> between [<表名2>.] <列名2> and [<表名2>.] <列名3>
1) 等值与非等值连接查询
当连接运算符为=时,称为等值连接。使用其他运算符称为非等值连接。
连接谓词中的列名称为连接字段。连接条件中的各连接字段类型必须是可比的,但名字不必相同。
- 等值连接
等值连接的运算符是=。
示例:查询每个学生及其选修课程的情况。
SELECT *
FROM Student,SC
WHERE Student.Sno = SC.Sno;
查询结果:
Student.Sno Sname Ssex Sage Sdept SC.Sno Cno Grade
95001 李勇 男 20 CS 95001 1 92
95001 李勇 男 20 CS 95001 2 85
95001 李勇 男 20 CS 95001 3 88
95002 刘晨 女 19 IS 95002 2 90
95002 刘晨 女 19 IS 95002 3 80
注:引用两表中同名属性时,必须加表名前缀区分。引用唯一属性名时可以加也可以省略表名前缀。
若在等值连接中把目标列中重复的属性列去掉则为自然连接。
- 非等值连接
不是 = 的连接操作就是非等值连接。
示例:查询选课信息,并显示成绩级别
SELECT Sno,Cno,Grade,Stage
FROM Sc, Gstage
WHERE Grade BETWEEN Low AND High;
2) 自身连接
一个表与其自己进行连接,称为表的自身连接。
示例:查询每一门课的先行课名
SELECT First.Cname 课名, Second.Cname 先行课名
FROM Course First,course Second
WHERE First.Cpno = Second.Cno;
输出:
课名 先行课名
数据库 数据结构
信息系统 数据库
注:需要给表起别名以示区别如示例中的First和Second;由于所有属性名都是同名属性,因此必须使用别名前缀,如示例中的First.Cname和Second.Cname。
3) 外连接(Outer Join)
普通连接操作只输出满足连接条件的元组。有时想保留不满足条件的元组,比如说以Student表为主体列出每个学生的基本情况及其选课情况,若某个学生没有选课,但是依旧想保留该学生的信息,这时需要使用到的就是外连接。实现方式就是以Student表为主体,对每一个学生如果没有选课信息则选课表的属性上填空值(Null)。
示例:查询每个学生及其选修课程的情况(包括没有选修课程的学生)
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student,SC
WHERE Student.Sno *= SC.Sno;
或
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student LEFT OUTER JOIN SC ON Student.Sno = SC.Sno;
查询结果:
Student.Sno Sname Ssex Sage Sdept Cno Grade
95001 李勇 男 20 CS 1 92
95001 李勇 男 20 CS 2 85
95001 李勇 男 20 CS 3 88
95002 刘晨 女 19 IS 2 90
95002 刘晨 女 19 IS 3 80
95003 王敏 女 18 MA null null
95004 张立 男 19 IS null null
外连接类型:
- 左外连接
将左边关系的不满足连接条件的行输出
WHERE 子句方式(*出现在左边):
WHERE R.A1 *= S.A1
FROM子句方式:
FROM R LEFT [OUTER] JOIN S ON R.A1=S.A1
- 右外连接
将右边关系的不满足连接条件的行输出
WHERE 子句方式(*出现在右边) :
WHERE R.A1 =* S.A1
FROM子句方式:
FROM R RIGHT [OUTER] JOIN S ON R.A1=S.A1
- 全外连接
将两边关系的不满足连接条件的行输出
WHERE 子句方式(*出现在两边) :
WHERE R.A1 *=* S.A1
FROM子句方式:
FROM R FULL [OUTER] JOIN S ON R.A1=S.A1
4) 复合条件连接
上面各个连接查询中,WHERE字句中只有一个查询条件。WHERE字句中可以有多个连接条件,称为复合条件连接。
示例:查询选修2号课程且成绩在90分以上的所有学生
Select Student.sno, sname
From student, sc
Where student.sno = sc.sno
And sc.cno = ‘2’
And sc.grade > 90;
4.3 嵌套查询
1) 嵌套查询概述
一个SELECT-FROM-WHERE语句称为一个查询块。将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询称为嵌套查询。
示例:嵌套查询
SELECT Sname /*外层查询或父查询*/
FROM Student
WHERE Sno IN
(SELECT Sno /*内层查询/子查询*/
FROM SC
WHERE Cno= \' 2 \');
注:子查询中不能使用Order by。
2) 嵌套查询分类
- 不相关子查询:子查询的查询条件不依赖于父查询
- 相关子查询:子查询的查询条件依赖于父查询
3) 引出子查询的谓词
- 带有IN谓词的子查询
在嵌套查询中,子查询的结果往往是一个集合,所以谓词IN是嵌套查询中最经常使用的谓词。
示例:查询与“刘晨”在同一个系学习的学生。
此查询要求可以分步来完成
① 确定“刘晨”所在系名
SELECT Sdept
FROM Student
WHERE Sname= \' 刘晨 \';
结果为:
Sdept
IS
② 查找所有在IS系学习的学生。
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept= \' IS \';
结果为:
Sno Sname Sdept
95001 刘晨 IS
95004 张立 IS
③ 将第一步查询嵌入到第二步查询的条件中
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 ③ 最后在Student关系中
FROM Student 取出Sno和Sname
WHERE Sno IN
(SELECT Sno ② 然后在SC关系中找出选
FROM SC 修了3号课程的学生学号
WHERE Cno IN
(SELECT Cno ① 首先在Course关系中找出“信
FROM Course 息系统”的课程号,结果为3号
WHERE Cname= ‘信息系统’));
或
SELECT Student.Sno,Sname
FROM Student,SC,Course
WHERE Student.Sno = SC.Sno AND
SC.Cno = Course.Cno AND
Course.Cname=‘信息系统’;
- 带有比较运算符的子查询
指父查询与子查询之间用比较运算符进行连接,当能确切知道内层查询返回单值时,可用比较运算符(=,>,<,>=,<=,!=或< >)。
示例:假设只有一个学生刘晨,则对上例可以用 = 代替IN :
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept =
(SELECT Sdept
FROM Student
WHERE Sname= ‘刘晨’);
示例:查询比刘晨年龄大的学生号,姓名 :
SELECT Sno,Sname
FROM Student
WHERE Sage >
(SELECT Sage
FROM Student
WHERE Sname= ‘刘晨’);
- 在HAVING中使用子查询
示例: 查询平均分大于95002这个学生的平均分的学号
SELECT SNO FROM SC
GROUP BY SNO
HAVING AVG(GRADE)>
(SELECT AVG(GRADE)
FROM SC
WHERE SNO=95002
)
- 带有EXISTS谓词的子查询
EXISTS谓词相当于存在量词$。带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“TRUE”或逻辑假值“false”:
-
- 若内层查询结果非空,则返回真值
- 若内层查询结果为空,则返回假值
由EXISTS引出的子查询,其目标列表达式通常都用* ,因为带EXISTS的子查询只返回真值或假值,给出列名无实际意义。由EXISTS引出的子查询一般都是相关子查询。所有其他谓词的子查询都能用带EXISTS谓词的子查询等价替换;一些带EXISTS或NOT EXISTS谓词的子查询不能被其他形式的子查询等价替换。
示例:查询所有选修了1号课程的学生姓名
- 用IN子查询实现:
SELECT Sname
FROM Student
WHERE Sno IN (Select Sno
FROM sc
WHERE Cno= ‘1’);
- 用连接运算实现:
SELECT distinct Sname
FROM Student, SC
WHERE Student.Sno=SC.Sno
AND SC.Cno= \'1\';
- 用EXISTS语句实现:
SELECT Sname FROM Student
WHERE EXISTS
(SELECT *
FROM SC /*相关子查询*/
WHERE Sno=Student.Sno AND Cno= \'1\');
4.4 集合查询
Select语句的查询结果是元组的集合,所以多个select语句的结果可进行集合操作。集合操作主要包括并操作(union)、交操作(intersect)和差操作(except)。注意:参加集合操作的各查询结果的列数必须相同;对应项的数据类型也必须相同。
1) 并操作
形式
<查询块>
UNION
<查询块>
示例:查询计算机科学系的学生与年龄不大于19岁的学生的并集。
方法一:并操作会自动去除相同记录,而union all则不会
SELECT *
FROM Student
WHERE Sdept= \'CS\'
UNION
SELECT *
FROM Student
WHERE Sage<=19;
方法二:
SELECT DISTINCT *
FROM Student
WHERE Sdept= \'CS\' OR Sage<=19;
2) 交操作
示例:查询计算机科学系的学生与年龄不大于19岁的学生的交集
SELECT *
FROM Student
WHERE Sdept=\'CS\'
INTERSECT
SELECT *
FROM Student
WHERE Sage<=19
实际上就是查询计算机科学系中年龄不大于19岁的学生:
SELECT *
FROM Student
WHERE Sdept= \'CS\' AND Sage<=19;
3) 差操作
示例1:查询计算机科学系的学生与年龄不大于19岁的学生的差集。
SELECT *
FROM Student
WHERE Sdept=\'CS\'
MINUS
SELECT *
FROM Student
WHERE Sage <=19;
实际上是查询计算机科学系中年龄大于19岁的学生:
SELECT *
FROM Student
WHERE Sdept= \'CS\' AND Sage>19;
示例2:查询未选课的学号(所有学号与选过课的学号的差集)
SELECT Sno
FROM Student
EXCEPT
SELECT Sno
FROM SC;
NOT IN实现:
SELECT Sno
FROM Student
WHERE Sno NOT IN
(SELECT Sno
FROM SC);
NOT EXISTS实现:
SELECT Sno
FROM Student S
WHERE NOT EXISTS
(SELECT *
FROM SC WHERE SC.SNO=S.SNO);
实际应用中交操作和差操作应用较少,并操作使用较多。
4.5 SELECT语句的一般格式
SELECT [ALL|DISTINCT] <目标列表达式> [别名] [ ,<目标列表达式> [别名]] …
FROM <表名或视图名> [别名] [,<表名或视图名> [别名]] …
[WHERE <条件表达式>]
[GROUP BY <列名1>[,<列名1’>] ...[HAVING <条件表达式>] ]
[ORDER BY <列名2> [ASC|DESC] [,<列名2’> [ASC|DESC] ] … ];
5 数据更新
数据更新操作有3种:向表中添加若干行数据、修改表中的数据和删除表中的若干行数据。在SQL中有相应的三类语句。
5.1 插入数据
SQL的数据插入语句INSERT通常有两种形式。一种是插入一个元组,另一种是插入子查询结果。后者可以一次插入多个元组。
1) 插入单个元组
语句格式:
INSERT
INTO <表名> [(<属性列1>[,<属性列2 >…)]
VALUES (<常量1> [,<常量2>] …)
其功能是将新元组插入指定表中。其中新元组的属性列1的值为常量1,属性列2的值为常量2,…。INTO子句中没有出现的属性列,新元组在这些列上将取空值。但必须注意的是,在表定义时说明了not null的属性列不能取空值,否则会出错。
示例:插入一条选课记录( \'95020\',\'1 \'),新插入的记录在Grade列上取空值
INSERT
INTO SC(Sno,Cno)
VALUES (\' 95020 \',\' 1 \');
示例:将一个新学生记录(学号:95020;姓名:陈冬;性别:男;所在系:IS;年龄:18岁)插入到Student表中。
INSERT
INTO Student(sno,sname,ssex,sdept,sage)
VALUES (\'95020\',\'陈冬\',\'男\',\'IS\',18);
或
INSERT INTO Student VALUES (\'95020\',\'陈冬\',\'男\',\'IS\',18);
注:当新元组在所有属性列上都指定了值,并且顺序一致,则可以省略属性名
INTO子句:
- 指定要插入数据的表名及属性列
- 属性列的顺序可与表定义中的顺序不一致
- 没有指定属性列:表示要插入的是一条完整的元组,且属性列属性与表定义中的顺序一致
- 指定部分属性列:插入的元组在其余属性列上取空值
VALUES子句 :
- 提供的值必须在值的个数和值的类型与INTO子句匹配
2) 插入子查询结果
子查询不仅可以嵌套在select语句中,用以构造父查询的条件,也可以嵌套在insert语句中,用以生成要插入的批量数据。
语句格式:
INSERT
INTO <表名> [(<属性列1> [,<属性列2>… )]
子查询;
示例:对每一个系,求学生的平均年龄,并把结果存入数据库。
第一步:建表
CREATE TABLE Deptage
(Sdept CHAR(15) /* 系名*/
Avgage INT); /*学生平均年龄*/
第二步:插入数据
INSERT
INTO Deptage(Sdept,Avgage)
SELECT Sdept,AVG(Sage)
FROM Student
GROUP BY Sdept;
5.2 修改数据
修改操作又称为更新操作,其一般语句格式:
UPDATE <表名>
SET <列名>=<表达式>[,<列名>=<表达式>]…
[WHERE <条件>];
其功能是修改指定表中满足WHERE子句条件的元组。其中set子句给出<表达式>[的值用于取代相应的属性值。如果省略WHERE子句,则表示要修改表中的所有元组。
修改指定表中满足WHERE子句条件的元组。
1) 修改某一个元组的值
示例:将学生95001的年龄改为22岁。
UPDATE Student
SET Sage=22
WHERE Sno=\' 95001 \';
2) 修改多个元组的值
示例1:将所有学生的年龄增加1岁。
UPDATE Student
SET Sage= Sage+1;
示例2:将信息系所有学生的年龄增加1岁。
UPDATE Student
SET Sage= Sage+1
WHERE Sdept=\' IS \';
3) 带子查询的修改语句
示例:将计算机科学系全体学生的成绩置零。
UPDATE SC
SET Grade=0
WHERE SNO IN
(SELETE SNO
FROM Student
WHERE SDEPT=‘CS’);
5.3 删除数据
删除语句的一般格式为:
DELETE
FROM <表名>
[WHERE <条件>];
DELETE语句的功能是删除指定表中满足WHERE子句条件的所有元组。如果省略WHERE子句表示要删除表中所有元组,但是表的定义仍在字典中。
1) 删除某一个元组的值
示例:删除学号为95019的学生记录。
DELETE
FROM Student
WHERE Sno=\'95019\';
2) 删除多个元组的值
示例:删除2号课程的所有选课记录。
DELETE
FROM SC;
WHERE Cno=\'2\';
示例:删除所有的学生选课记录。
DELETE
FROM SC;
3) 带子查询的删除语句
以上是关于关系数据库标准语言SQL的主要内容,如果未能解决你的问题,请参考以下文章