写在前面的话
注意:本章非非非非非非非常的长,复习党只需要看3.3-3.6即可。
3.1 学生-课程数据库
学生-课程模式S-T :
学生表:Student(Sno,Sname,Ssex,Sage,Sdept)
课程表:Course(Cno,Cname,Cpno,Ccredit)
学生选课表: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.2 数据查询概念(了解即可)
语句格式
SELECT [ALL|DISTINCT]<目标列表达式>[,<目标列表达式>]..
FROM<表名或视图名[,<表名或视图名>]...
[WHERE<条件表达式>]
[GROUP BY<列名1>[HAVING<条件表达式>]]
[ORDER BY<列名2>[ASCIDESC]];
SQL基本结构包括3个子句
- SELECT子句
- 对应
投影运算
,指定查询结果中所需要的属性或表达式-
- 对应
- FROM子句
- 对应
笛卡尔积
,给出查询所涉及的表,表可以是基本表、视图或查询表
- 对应
- WHERE子句
- 对应选择运算,指定查询结果元组所需要满足的选择条件
SELECT和FROM是必须的,其他是可选的
- 对应选择运算,指定查询结果元组所需要满足的选择条件
基本语法
SELECT A1,A2,....,An
FROM R1,R2,...,Rm
WHERE P
- A1,A2,…,A,代表需要查找的
属性或表达式
- R,R2,…,Rm代表
查询所涉及的表
- P代表
谓词(即选择条件)
,如果省略WHERE子句,表示P为真SQL的查询结果中允许包含重复元组
SQL执行过程:
- 首先对R,R2,…,Rm执行笛卡尔积
- 然后在笛卡尔积中选择使得谓词P为真的记录
- 再在A1,A,…A,属性列中进行投影运算,不消除重复元组
- 如需消除重复元组,必须使用关键字DISTINCT
3.3 数据定义
3.3.1 创建基本表
(1)基本格式
CREATE TABLE <表名>
(<列名> <数据类型>[ <列级完整性约束条件> ]
[,<列名> <数据类型>[ <列级完整性约束条件>] ] …
[,<表级完整性约束条件> ] );
(2)完整性约束条件
- 列值非空(NOT NULL)
- 列值唯一(UNIQUE)
- 查列值是否满足一个布尔表达式(CHECK)
(3)数据类型
| 数据类型 | 含义 | | —- | —- | | CHAR(n) | 长度为n的定长字符串 | | VARCHAR(n) | 最大长度为n的变长字符串 | | INT | 长整数(也可以写作INTEGER) | | SMALLINT | 短整数 | | NUMERIC(p,d) | 定点数,由p位数字(不包括符号、小数点)组成,小数后面有d位数字 | | REAL | 取决于机器精度的浮点数 | | Double Precision | 取决于机器精度的双精度浮点数 | | FLOAT(n) | 浮点数,精度至少为n位数字 | | DATE | 日期,包含年、月、日,格式为YYYY-MM-DD | | TIME | 时间,包含一日的时、分、秒,格式为HH:MM:SS |
其中黄色标记的是常用的。
举个例子:
CREATE TABLE Student
(Sno CHAR(9) PRIMARY KEY, /* 列级完整性约束条件*/
Sname CHAR(20) UNIQUE, /* Sname取唯一值*/
Ssex CHAR(2) CHECK (Ssex IN (‘男’,‘女’),
Sage SMALLINT NOT NULL,
Sdept CHAR(20)
);
3.3.2 修改基本表
ALTER TABLE <表名>
[ ADD <新列名> <数据类型> [ 完整性约束 ] ]
[ DROP <完整性约束名> ]
[ ALTER COLUMN<列名> <数据类型> ];
3.3.3 删除基本表
DROP TABLE <表名>[RESTRICT| CASCADE]
- RESTRICT:
- 删除表是有限制的。欲删除的基本表不能被其他表的约束所引用
- 如果存在依赖该表的对象,则此表不能被删除
- CASCADE:删除该表没有限制。
- 在删除基本表的同时,相关的依赖对象一起删除
3.4数据查询
3.4.1单表查询
(1)选择表中的若干列
[例1]查询全体学生的学号与姓名。
SELECT Sno,Sname
FROM Student;
该查询的执行过程是:
- 从Student表中依次取出每个元组
- 对每个元组仅选取Sno、Sname两个属性的值,形成一个新元组
- 最后将这些新元组组织为一个结果关系输出
[例2]查询全体学生所有信息。
SELECT *
FROM Student;
这里的
*****
符号表示查询所有内容。
给属性取列别名:
[例3]查询所有学生的所属系、学号和姓名,要求用中文显示列名
SELECT Sdept 所属系,Sno 学号,Sname 姓名
FROM Student
也可以使用AS关键词取别名
SELECT Sdept AS 所属系,Sno AS 学号,Sname AS 姓名
FROM Student
查询经过计算的值:
[例4]查全体学生的姓名及其出生年份。
SELECT Sname,2020-Sage /*假定当年的年份为2020年*/
FROM Student;
输出结果:
Sname | 2020-Sage |
---|---|
李勇 | 2000 |
刘晨 | 2001 |
王敏 | 2002 |
张立 | 2001 |
[例5]查询全体学生的姓名、出生年份和所有系,要求用小写字母表示所有系名:
SELECT Sname NAME, 'Year of Birth:'BIRTH,year(GETDATE())-Sage BIRTHDAY,LOWER(Sdept) DEPARTMENT
FROM Student;
- 函数lower()将大写字母改为小写字母函数
- getdate()获取当前系统的日期·函数
- year()提取日期中的年份
'Year of Birth:'BIRTH
表示BIRTH这一列的值全是Year of Birth:
(2)选择表中的若干组元素
取消重复的行:
执行上面的SELECT语句后,结果为:SELECTALL Sno
FROM SC;
Sno |
---|
200215121 |
200215121 |
200215121 |
200215122 |
200215122 |
指定DISTINCT关键词,去掉表中重复的行
SELECT DISTINCT Sno
FROM SC;
结果为:
Sno |
---|
200215121 |
200215122 |
选择运算
就是运用WHERE句子对数据进行筛选,常用的筛选语句有如下几个。
- 比较运算:>、>=、<、<=、=、<>(或!=)
- 范围查询:BETWEEN…AND
- 集合查询:IN
- 空值查询:IS NULL
- 字符匹配查询:LIKE
- 逻辑查询:AND、OR、NOT
下面举几个例子:
[例6]查询计算机科学系(CS)全体学生的名单。
SELECT Sname
FROM Student
WHERE Sdept='CS';
[例7]查询所有出生日期在2002年以前的学生姓名及其年龄。
SELECT Sname,Sage
FROM Student
WHERE year(GETDATE())-Sage <2002;
选择查询的方法主要有两种:
- 全表扫描法
- 索引搜索法
一般来讲索引搜索法效率更高,因为全表扫描法需要遍历全表。
[例8]查询年龄在20~23岁(包括20岁和23岁)之间的学生的姓名、系别和年龄
SELECT Sname,Sdept,Sage
FROM Student
WHERE Sage BETWEEN 20 AND 23;
不在范围内就使用
NOT BETWEEN ... AND ...
[例9]查询信息系(IS)、数学系(MA)和计算机科学系(CS)学生的姓名和性别。
SELECT Sname,Ssex
FROM Student
WHERE Sdept IN ( 'IS','MA','CS');
IN
表示查询属性值在集合内的元组。IN
是全表扫描 如果想要查询不存在集合内的则使用NOT IN
字符串匹配
**%**
表示任意长度的字符串- ab%,表示所有以ab开头的任意长度的字符串;(例如abcd)
- zhang%ab,表示以zhang开头,以ab结束,中间可以是任意个字符的字符串。(例如zhang123ab)
**符号_(下划线)**
表示任意一个字符- ab_,表示所有以ab开头的3个字符的字符串,其中第3个字符为任意字符;(例如abc)
- a__b表示所有以a开头,以b结束的4个字符的字符串,且第2、3个字符为任意字符。(例如:acbb)
[例10]查询所有姓刘学生的姓名、学号和性别。
SELECT Sname,Sno,Ssex
FROM Student
WHERE Sname LIKE‘刘%';
使用转义字符
[例11]查询DB_Design课程的课程号和学分。
SELECT Cno,Ccredit
FROM Course
WHERE Cname LIKE 'DB\_Design' ESCAPE '\';
ESCAPE'\'
表示“\”为换码字符。
涉及空值的查询
谓词:IS NULL或IS NOT NULL“IS”不能用“=”代替
[例12]某些学生选修课程后没有参加考试,所以有选课记录,但没有考试成绩。查询缺少成绩的学生的学号和相应的课程号。
SELECT Sno,Cno
FROM SC
WHERE Grade IS NULL
多重条件的查询
逻辑运算符:AND和 OR来联结多个查询条件
- AND的优先级高于OR
- 可以用括号改变优先级
[例13]查询计算机系年龄在20岁以下的学生姓名。
SELECT Sname
FROM Student
WHERE Sdept= 'CS' AND Sage<20;
(3)ORDER BY子句
- ORDER BY子句
- 可以按一个或多个属性列排序
- 升序:ASC;降序:DESC;缺省值为升序
+当排序列含空值时 - ASC:排序列为空值的元组最后显示
- DESC:排序列为空值的元组最先显示
[例14]查询选修了3号课程的学生的学号及其成绩,查询结果按分数降序排列。
SELECT Sno,Grade
FROM SC
WHERE Cno= ' 3 '
ORDER BY Grade DESC;
(4)聚集函数
- 计数
- COUNT ([DISTINCT|ALL]*)
- COUNT ([DISTINCT|ALL]<列名>)
- 计算总和
- SUM([DISTINCT|ALL]<列名>)
- 计算平均值
- AVG ([DISTINCTALL]<列名>)
- 最大最小值
- MAX ([DISTINCT|ALL]<列名>)
- MIN ([DISTINCTALL]<列名>)
[例15]查询学生总人数。
SELECT COUNT(*)
FROM Student;
[例16]查询选修了课程的学生人数。
SELECT COUNT(DISTINCT Sno)
FROM SC;
[例17]计算1号课程的学生平均成绩。
SELECT AVG(Grade)
FROM SC
WHERE Cno= '1 ';
(5)GROUP BY 子句
该子句的作用是细化聚集函数的作用对象
- 未对查询结果分组,聚集函数将作用于整个查询结果
- 对查询结果分组后,聚集函数将分别作用于每个组作用对象
- 是查询的中间结果表
- 按指定的一列或多列值分组,值相等的为一组
举个例子:CS表
学号(Sno) | 课程号(Cno) | 成绩(Grade) |
---|---|---|
200215121 | 1 | 92 |
200215121 | 2 | 85 |
200215121 | 3 | 88 |
200215122 | 2 | 90 |
200215122 | 3 | 80 |
对该表使用GROUP BY Sno
子句,则会划分出如下分组。
学号(Sno) | 课程号(Cno) | 成绩(Grade) |
---|---|---|
200215121 | 1 | 92 |
200215121 | 2 | 85 |
200215121 | 3 | 88 |
学号(Sno) | 课程号(Cno) | 成绩(Grade) |
---|---|---|
200215122 | 2 | 90 |
200215122 | 3 | 80 |
分组之后聚集函数作用的对象就是分组之后的相关属性。
[例18]求各个课程号及相应的选课人数。
SELECT Cno, COUNT(Sno) 选课人数
FROM SC
GROUP BY Cno ;
(6)HAVING语句
HAVING短语与WHERE子句的区别:作用对象不同
- WHERE子句作用于基表或视图,从中选择满足条件的元组。
- HAVING短语作用于组,从中选择满足条件的组。
简单的来讲,WHERE子句用于属性的条件查询,HAVING子句用于聚集函数的条件查询。
[例19]查询有3门以上课程是90分以上的学生的学号及(90分以上的)课程数。
SELECT Sno,COUNT(*)
FROM SC
WHERE Grade>=90
GROUP BY Sno
HAVING COUNT(*)>=3;
注意:HAVING子句必须跟着GROUP子句之后。
接着来一个例题复习一下前面的内容
查询各个专业的选修课程总学时大于10个学时的专业号和选修课程总学时,并按降序排序
select dbo.课程.专业,sum(dbo.课程.学时)
from dbo.课程
where dbo.课程.课程类别='选修课程'
group by dbo.课程.专业
having sum(dbo.课程.学时)>10
order by sum(dbo.课程.学时) desc
几个注意点: 1.大小写不区分。 2.
dbo
是表名的前缀,可以忽略不写。 3.课程.XX表示课程表里面的XX元组。
3.4.2 连接查询
(1)基本定义
连接条件或连接谓词:用来连接两个表的条件一般格式:
[<表名1>.]<列名1> <比较运算符> [K<表名2>.]<列名2>
[<表名1>.]<列名1> BETWEEN [<表名2>.]<列名2> AND [<表名2>.]<列名3>
- 连接字段:连接谓词中的列名称
- 连接条件中的各连接
字段类型
必须是可比的,但名字不必是相同的一般情况下都是等值连接,所以比较运算符一般为
=
。
[例20]查询每个学生及其选修课程的情况
SELECT Student.*,SC.*
FROM Student,SC
WHERE Student.Sno = SC.Sno;
(2)自身连接
自身连接:一个表与其自己进行连接,需要给表起别名以示区别
由于所有属性名都是同名属性,因此必须使用别名前缀。
Cno | Cname | Cpno | Ccredit |
---|---|---|---|
1 | 数据库 | 5 | 4 |
2 | 数学 | 2 | |
3 | 信息系统 | 1 | 4 |
4 | 操作系统 | 6 | 3 |
5 | 数据结构 | 7 | 4 |
6 | 数据处理 | 2 | |
7 | PASCAL语言 | 6 | 4 |
[例21]查询每一门课的间接先修课(即先修课的先修课)
SELECT FIRST.Cno, SECOND.Cpno
FROM Course FlRST,Course SECOND
WHERE FIRST.Cpno = SECOND.Cno;
(3)外连接
外连接与普通连接的区别
- 普通连接操作只输出满足连接条件的元组
- 外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出
- 左外连接 (LEFT OUT JOIN)
- 列出左边关系(如本例Student)中所有的元组
- 右外连接(RIGHT OUT JOIN)
- 列出右边关系中所有的元组
举个例子:
[例22]查询每个(所有)学生及其选修课程的情况
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student LEFT OUT JOIN SC ON(Student.Sno=SC.Sno); //左外连接
查询之后的表如下:
Sno | Sname | Ssex | Sage | Sdept | Cno | Grade |
---|---|---|---|---|---|---|
200215121 | 李勇 | 男 | 20 | CS | 1 | 92 |
200215121 | 李勇 | 男 | 20 | CS | 2 | 85 |
200215121 | 李勇 | 男 | 20 | CS | 3 | 88 |
200215122 | 刘晨 | 女 | 19 | CS | 2 | 90 |
200215122 | 刘晨 | 女 | 19 | CS | 3 | 80 |
200215123 | 王敏 | 女 | 18 | MA | NULL | NULL |
200215125 | 张立 | 男 | 19 | IS | NULL | NULL |
(4)符合条件连接
也就是WHERE子句中含多个连接条件
[例23]查询选修2号课程且成绩在90分以上的所有学生
SELECT Student.Sno,Sname
FROM Student, SC
WHERE Student.Sno = SC.Sno
AND SC.Cno= '2'AND SC.Grade > 90;
3.4.3 嵌套查询
(1)嵌套查询概述
- 一个
SELECT-FROM-WHERE语句
称为一个查询块 - 将一个查询块嵌套在另一个查询块的
WHERE子句或HAVING短语的条件中
的查询称为嵌套查询
举个例子:
SELECT Sname
/*外层查询/父查询*/
FROM Student
WHERE Sno IN
(SELECT Sno
FROM Sc
WHERE Cno= '2 ') ;/*内层查询/子查询*
一些性质
- 子查询的限制
- 不能使用ORDER BY子句
- 层层嵌套方式反映了SQL语言的结构化
- 有些嵌套查询可以用连接运算替代
相关子查询和不相关子查询
- 不相关子查询
- 子查询的查询条件不依赖于父查询
- 由里向外逐层处理。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。
- 相关子查询
- 子查询的查询条件依赖于父查询
- 首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表
- 然后再取外层表的下一个元组
- 重复这一过程,直至外层表全部检查完为止
(2)带有IN谓词的子查询
[例24]查询与“刘晨”在同一个系学习的学生。
这里的步骤就是:
1.首先选择出刘晨所在的系
2.再去从这个系里面选择学生。
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 = '刘晨';
该题是不相关子查询,因为子查询的WHERE条件不依赖于父查询的WHERE条件。
(3)带有比较运算符的子查询
[例25]找出每个学生超过他选修课程平均成绩的课程号。
SELECT Sno,Cno
FROM SC x
WHERE Grade >=(SELECT AVG(Grade)
FROM SC y
WHERE y.Sno=x.Sno);
该题是相关子查询。因为子查询的条件中,依赖于父查询的条件。
(4)带有ANY(SOME)或者ALL谓词的子查询
谓词语义:
ANY
:任意一个值ALL
:所有值
简单来讲,出现某一就用谓词
ANY
,出现所有就用ALL
配合使用其他比较运算符
>ANY 大于子查询结果中的某个值
> ALL 大于子查询结果中的所有值
<ANY 小于子查询结果中的某个值
<ALL 小于子查询结果中的所有值
>=ANY 大于等于子查询结果中的某个值
>= ALL 大于等于子查询结果中的所有值
<= ANY 小于等于子查询结果中的某个值
<= ALL 小于等于子查询结果中的所有值
=ANY 等于子查询结果中的某个值
=ALL 等于子查询结果中的所有值(通常没有实际意义)
!=(或<>)ANY 不等于子查询结果中的某个值
!=(或<>)ALL 不等于子查询结果中的任何一个值
[例26]查询其他系中比计算机科学某一学生年龄小的学生姓名和年龄
SELECT Sname,Sage
FROM Student
WHERE Sage <ANY(
SELECT Sage
FROM Student
WHERE Sdept= 'CS'
)AND Sdept != 'CS'
[例27]求年龄大于所有信息系女同学年龄的男学生姓名和年龄
SELECT Sname, Sage
FROM Student
WHERE Ssex='男'
AND Sage > ALL (SELECT Sage
FROM Student
WHERE Ssex='女' and Sdept='lS');
(5)带有EXISTS谓词的子查询
带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值**true**
或逻辑假值**false**
。
若内层查询结果非空,则外层的WHERE子句返回真值 若内层查询结果为空,则外层的WHERE子句返回假值
NOT EXISTS谓词
若内层查询结果非空,则外层的WHERE子句返回假值 若内层查询结果为空,则外层的WHERE子句返回真值
由EXISTS引出的子查询,其目标列表达式通常都用*
,因为带EXISTS的子查询只返回真值或假值,给出列名无实际意义
举个例子:
用嵌套查询
SELECT Sname
FROM Student
WHERE EXISTS
(SELECT *
FROM SC
WHERE SC.Sno=Student.Sno AND Cno= '1 ');
一般情况下exits引导的子查询都是相关子查询。
[例28]查询与“刘晨”在同一个系学习的学生。可以用带EXISTS谓词的子查询替换:
SELECT Sno,Sname,Sdept
FROM Student S1
WHERE EXISTS
(SELEC T*
FROM Student S2
WHERE S2.Sdept = S1.Sdept AND
S2.Sname =‘刘晨’);
[例29]查询选修了全部课程的学生姓名。
可将题目的意思转换成等价的形式:查询这样的学生,没有一门课程是他不选修的
SELECT Sname
FROM Student
WHERE NOT EXISTS
(SELECT*
FROM Course
WHERE NOT EXISTS //--判断学生Student.Sno没有选修课程Course.Cno
(SELECT*
FROM sc
WHERE Sno= Student.Sno
AND Cno= Course.Cno)
) ;
3.4.4 集合查询
集合操作的种类
- 并操作 UNION
- 交操作 INTERSECT
- 差操作 EXCEPT
(1)并操作
[例30]查询计算机科学系的学生及年龄不大于19岁的学生。
方法一:SELECT*
FROM Student
WHERE Sdept= 'SCS'
UNION
SELECT*
FROM Student
WHERE Sage<=19;
UNION:将多个查询结果合并起来时,系统自动去掉重复元组。 UNION ALL:将多个查询结果合并起来时,保留重复元组。
方法二:
SELECT DISTINCT*
FROM Student
WHERE Sdept= 'CS'OR Sage<=19;
(2)交集操作
[例31]查询计算机科学系的学生与年龄不大于19岁的学生的交集
SELECT*
FROM Student
WHERE Sdept='Cs'
INTERSECT
SELECT*
FROM Student
WHERE Sage<=19
(3)差集操作
[例32]查询计算机科学系的学生与年龄不大于19岁的学生的差集。
SELECT *
FROM Student
WHERE Sdept='CS'
EXCEPT
SELECT *
FROM Student
WHERE Sage <=19;
3.5 数据更新
3.5.1 数据的增加
数据的插入
语句格式
INSERT
INTO <表名>[(<属性列1>[,<属性列2>...)]
VALUES(<常量1>[,<常量2>]
)
INTO子句
属性列的顺序可与表定义中的顺序不一致 没有指定属性列 指定部分属性列
VALUES子句
提供的值必须与INTO子句匹配 值的个数 值的类型
举个例子:
[例33]将一个新学生元组(学号:200215128;姓名:陈冬;性别:男;所在系:IS;年龄:18岁)插入到Student表中。
INSERT
INTO
Student (Sno,Sname,Ssex,Sdept,Sage)
VALUES ('200215128','陈冬','男','IS',18);
没有明确赋值的属性会被自动赋予NULL值。
插入子查询结果
语句格式
INSERT
INTO<表名>[(<属性列1>[,<属性列2>... )]
子查询;
[例34]对每一个系,求学生的平均年龄,并把结果存入数据库。
第一步:建表
CREATE TABLE Dept_age
(Sdept CHAR(15)/*系名*l
Avg_age SMALLINT);/*学生平均年龄*/
第二步:插入数据
INSERT
INTO
Dept_age(Sdept,Avg_age)
SELECT Sdept,AVG(Sage)
FROM Student
GROUP BY Sdept;
3.5.2 数据的删除
语句格式:
DELETE
FROM <表名>
[WHERE<条件>];
例子:
[例35]删除学号为200215128的学生记录。
DELETE
FROM Student
WHERE Sno= 200215128 ';
注意:delete的删除只是删除数据,不删除表本身。 删除整个表用drop。
[例36]删除男同学所有学分为3的课程的选课记录
DELETE
FROM SC
WHERE ‘男’=
(SELETE Ssex
FROM Student
WHERE Student.Sno=SC.Sno)
and 3=(SELETE Ccredit
FROM Course
WHERE Course.Cno = SC.Cno) ;
不能直接查询
Ssex='男'
,因为Ssex不是SC表中的属性。
3.5.3 数据的更新
语句格式
UPDATE <表名>
SET <列名>=<表达式[,<列名>=<表达式>]...
[WHERE <条件>];
例子:
[例37]将学生200215121的年龄改为22岁
UPDATE Student
SET Sage=22
WHERE Sno='200215121 ';
[例38]将所有学生的年龄增加1岁
UPDATE Student
SET Sage= Sage+1;
3.6 视图
(1)语句格式
CREATE VIEW
<视图名>[(<列名>[,<列名>]...)]
AS <Select查询语句>;
例如:
[例38]:建立信息系学生的视图。
CREATE VIEW IS_Student
AS
SELECT Sno,Sname,Sage
FROM Student
WHERE Sdept='IS';
SELECT Sno,Sage
FROM IS_Student
WHERE Sage<20;
撤销视图:DROP VIEW<视图名>;
例如:
DROPVIEW IS_Student;
视图可以理解为一个表,与基本表具有一样的性质,也可以像基本表一样使用。 大部分用于简化复杂的用户查询的操作。
(2)视图的特点
- 虚表,是从一个或几个基本表(或视图)导出的表
- 视图将导致性能开销,因为视图是动态生成的
- 基于视图的查询是受限的
- 视图的更新是受限的
- 只存放视图的定义,不存放视图对应的数据
- 基表中的数据发生变化,从视图中查询出的数据也随之改变
- 一定程度上保证了数据的逻辑独立性
(3)视图更新
格式:UPDATE SC
SET AVG(Grade)=90
WHERE Sno=‘200215121'
UPDATE
后面是需要更新的表SET
后面是需要更新的属性
(4)视图更新的限制
举个例子:
//S_G视图的子查询定义:
CREATE VIEW S_G (Sno,Gavg)
AS
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno
//将学号200215121的Gavg值更新为90
UPDATE S_G
SET Gavg=90
WHERE Sno=‘200215121’;
该视图只更新了平均成绩但是没有更新基本表表的各个学生的成绩。
以下情况视图不能更新
(1)若视图是由两个以上基本表导出的,则此视图不允许更新(SQL SERVER可以)。
(2)若视图的字段来自字段表达式或常数,则不允许对此视图执行INSERT和UPDATE操作,但允许执行DELETE操作。
(3)若视图的字段来自聚集函数,则此视图不允许更新。
(4)若视图定义中含有GROUP BY子句,则此视图不允许更新。
(5)若视图定义中含有DISTINCT短语,则此视图不允许更新。
(6)若视图定义中有嵌套查询,并且内层查询的FROM子句中涉及的表也是导出该视图的基本表,则此视图不允许更新。
(7)一个不允许更新的视图上定义的视图也不允许更新。
(5)视图的创建
语句格式
CREATE VIEW
<视图名>[(<列名>[,<列名>]...)]
AS <子查询>
[WITH CHECK OPTION];
组成视图的属性列名:全部省略或全部指定子查询不允许含有ORDER BY子句和DISTINCT短语
WITH CHECK OPTION 表示视图更新受限,一般情况都加上去。
3.7 触发器(了解即可)
(1)定义触发器
CREATE TRIGGER语法格式:
CREATE TRIGGER<触发器名> //定义触发器的名字
{BEFORE |AFTER}<触发事件>ON<表名> //before和after表示激活触发器的时间是在执行前还是后
REFERENCING NEW|OLD ROW AS<变量> //指出引用的变量
FOR EACH {Row | STATEMENT} //触发器的类型
[WHEN<触发条件>] //触发的条件
<触发动作体>
触发事件:INSERT、DELETE、UPDATE。 触发器类型
- 行级触发器(FOR EACH ROW)
- 语句级触发器(FOR EACH STATEMENT)
例如,假设在TEACHER表上创建了一个AFTER UPDATE触发器
。如果表TEACHER有1000行,执行如下语句:
UPDATE TEACHER SET Deptno=5;
- 如果该触发器为
语句级触发器
,那么执行完该语句后,触发动作只发生一次 - 如果是
行级触发器
,触发动作将执行1000次触发动作体 触发动作体可以是一个匿名PL/SQL过程块 也可以是对已创建存储过程的调用
[例39]定义一个AFTER触发器,为工资表定义完整性规则“教师的基本工资不得低于1000元,如果低于1000元,自动改为1000元”。
CREATE TRIGGER updateCheck
AFTER UPDATE //这里定义update是触发器事件
ON 工资
WHEN new.基本工资<1000 //new指的就是新插入的数据
BEGIN //这里是触发动作体,修改工资低于1000的老师的工资
UPDATE 工资
SET 基本工资=1000
WHERE 工资.职工号=new.职工号;
END;
(2)激活触发器
由触发事件自动激活。
一个数据表上可能定义了多个触发器
同一个表上的多个触发器激活时遵循如下的执行顺序:
(1)执行该表上的BEFORE触发器;
(2)激活触发器的SQL语句;
(3)执行该表上的AFTER触发器。
(3)删除触发器
删除触发器的SQL语法:
DROP TRIGGER<触发器名> ON <表名>;