关系数据库的数据更新包括插入、删除和修改三个方面的功能,这些功能均可以用 SQL 语言来实现。
3.4.1 插入数据
SQL 语言的数据插入通过 INSERT 语句实现,包括两类:插入单个元组和插入子查询结果。
1.插入单个元组
使用INSERT 语句实现插入单个元组的基本格式如下:
INSERT
INTO <表名> [(<属性列 1>[,<属性列 2>…]) VALUES (<常量 1>[,<常量 2>]…);
说明:
(1)该语句的功能是将新元组插入指定表中。
(2)若 INTO 子句中表名后有各属性列选项,则插入的新元组的属性列 1 的值为常量 1,
属性列2 的值为常量 2……。如果某些属性列在 INTO 子句中没有出现,则新记录在这些列上将 取空值。但必须注意的是,在表定义时说明了NOT NULL 的属性列不能取空值,否则会出错。
(3)若属性列表和常量值表的顺序与表结构中的顺序相同,且给所有的属性列都指定值,
则可以省略属性列表。
(4)VALUES 子句提供的值,不管是值的个数还是值的类型必须与 INTO 子句匹配,否 则系统会报错处理。
【例 3-52】将一个新学生记录(借书证号:080801;姓名:夏雨;性别:男;专业名:
计算机;出生年份:1989-09;办证日期:2008-12-27)插入 STUDENT 表中。
INSERT
INTO STUDENT(借书证号,姓名,性别,专业名,出生年份,办证日期)
VALUES ('080801','夏雨','男','计算机','1989-09','2008-12-27');
本例中,属性列表的顺序与表结构中的顺序不一致,因此不能省略INTO 子句中的属性列 表,但是如果本例表示为:
INSERT
INTO STUDENT(借书证号,姓名,专业名,性别,出生年份,办证日期)
VALUES ('080801', '夏雨', '计算机', '男','1989-09', '2008-12-27');
此时,属性列表的顺序与表结构中顺序相同,且为每个属性列都指定了值,此时可省略 属性列表,表示为:
INSERT INTO STUDENT
VALUES ('080801', '夏雨', '计算机', '男','1989-09', '2008-12-27');
【例3-53】插入一条图书记录('7800737985', '水煮三国', '成君忆', '中信出版社', '26.0')。
INSERT
INTO BOOK(ISBN,书名,作者,出版社,价格)
VALUES ('7800737985', '水煮三国', '成君忆', '中信出版社', '26.0');
则新插入的记录将在本数属性列上赋默认值0,在库存量列上自动赋空值,本例也可以表示为:
INSERT INTO BOOK
VALUES ('7800737985', '水煮三国', '成君忆', '中信出版社', 26.0, 0,NULL);
2.插入子查询结果
插入数据时,除了插入单个元组外,还可以将子查询嵌套在INSERT 语句中,从而插入子 查询的结果。插入子查询结果的INSERT 语句格式如下:
INSERT
INTO <表名> [(<属性列 1>[,<属性列 2>…)]
子查询;
该语句中,子查询用以生成要插入的数据,整个语句的功能是批量插入,一次将子查询 的结果全部插入指定表中。子查询中 SELECT 子句目标列不管是值的个数还是值的类型必须 与INTO 子句匹配。
【例3-54】在数据库新建一个表,存放 STUDENT 表中各专业的学生人数。
首先在数据库中新建一张表,存放各专业的名称及学生人数。
CREATE TABLE Major_num (专业名 char(12),
人数 int);
然后求得各专业的人数并插入新建的表中。
INSERT
INTO Major_num
SELECT 专业名,count(借书证号)
FROM STUDENT GROUP BY 专业名;
注意:DBMS 在执行插入语句时会检查所插元组是否破坏表上已定义的完整性规则,包 括实体完整性、参照完整性和用户定义的完整性。
3.4.2 修改数据
修改操作又称为更新操作,语句的一般格式如下:
UPDATE <表名>
SET <列名>=<表达式> [,<列名>=<表达式>]…
[WHERE <条件> ];
该语句的功能是修改指定表中满足WHERE 子句条件的元组。其中 SET 子句用于指定修 改方式、要修改的列和修改后的取值,即用<表达式>的值取代相应的属性列值。WHERE 子句 指定要修改的元组,如果省略WHERE 子句,则表示要修改表中的所有元组。
注意:DBMS 在执行修改语句时会检查所修改元组是否破坏表上已定义的完整性规则,
包括实体完整性(一些DBMS 规定主码不允许修改)、参照完整性和用户定义的完整性。
更新包括如下几种操作:
1.更新表中全部的数据
【例3-55】将所有学生的借书数清为 0。
UPDATE STUDENT SET 借书数=0;
2.更新表中某些元组的数据
【例3-56】将清华大学出版社的图书的复本数和库存量加 5。
UPDATE BOOK
SET 复本数=复本数+5,库存量=库存量+5 WHERE 出版社='清华大学出版社';
3.带子查询的修改
【例3-57】将计算机专业的所有学生的应还书日期改为 2009-01-01。
UPDATE BORROW
SET 应还时间='2009-01-01' WHERE 借书证号 IN
(SELECT 借书证号 FROM STUDENT
WHERE 专业名='计算机');
或表示为:
UPDATE BORROW
SET 应还时间='2009-01-01' WHERE '计算机'=
(SELECT 专业名 FROM STUDENT
WHERE 借书证号= BORROW.借书证号);
3.4.3 删除数据
删除语句的一般格式如下:
DELETE
FROM <表名>
[WHERE <条件> ];
该语句的功能是删除指定表中满足 WHERE 子句条件的元组,如果 WHERE 子句缺省表 示要删除表中的全部元组,但表的定义仍在数据字典中,即DELETE 语句删除的是数据库表 中的数据,而不是表的定义,注意与DROP 语句的用法进行区分。
删除包括如下几种操作:
1.删除某个(某些)元组的值
【例3-58】2005 级的学生毕业了,删除 STUDENT 表中 2005 级学生的记录(2005 级学 生的借书证号是以05 开头的)。
DELETE
FROM STUDENT
WHERE 借书证号 like '05%';
2.删除全部元组的值
【例3-59】清空借阅记录表。
DELETE
FROM BORROW;
3.带子查询的删除语句
【例3-60】删除计算机专业的所有学生的借阅记录。
DELETE FROM BORROW WHERE 借书证号 in (SELECT 借书证号 FROM STUDENT
WHERE 专业名='计算机');
或表示为:
DELETE FROM BORROW WHERE '计算机'=
(SELECT 专业名 FROM STUDENT
WHERE 借书证号=BORROW.借书证号);
注意:DBMS 在执行删除语句时,会检查所删元组是否破坏表上已定义的参照完整性规 则,检查是否不允许删除或是需要级联删除。
3.5 视图
视图是一种虚表,是从一个或几个基本表(或视图)导出的表,数据库中只存放视图的 定义而不存放视图的数据,这些数据仍存放在导出视图的基本表中。因此如果基本表中的数据 发生变化,那么从视图查询的数据也随之发生改变,因此有这样一个说法,视图就像一个窗口,
透过它可以看到数据库中自己感兴趣的数据及其变化。
一个用户可以定义若干个视图,因此,用户的外模式就由若干基本表和若干视图组成。
视图一旦被定义,就可以像基本表一样,可以对其查询和删除,在某些情况下还可以对其修改。
3.5.1 定义视图
在SQL 语言中,定义视图的基本语句如下:
CREATE VIEW <视图名>[(<列名>[,<列名>]…)]
AS <子查询>
[WITH CHECK OPTION];
该语句中,子查询可以是任意复杂的 SELECT 语句,可以来自一个表,也可以来自多个 表,还可以来自一个或多个视图。但一般来说,SELECT 语句中不允许含有 ORDER BY 子句 和DISTINCT 短语。
WITH CHECK OPTION 选项指出在视图上进行 UPDATE、INSERT、DELETE 操作时要符 合子查询中条件表达式所指定的限制条件。
【例3-61】建立计算机专业学生借阅图书的视图 CS_VIEW,包括学生的借书证号、姓名、
性别、所借书的ISBN 和借书时间,且要保证对该视图进行修改和插入操作时都是计算机专业 的学生。
CREATE VIEW CS_VIEW
AS SELECT STUDENT.借书证号,姓名,性别,ISBN,借书时间 FROM STUDENT,BORROW
WHERE STUDENT.借书证号= BORROW.借书证号 AND 专业名='计算机' WITH CHECK OPTION ;
【例3-62】创建一个视图 CS_VIEW_081010,该视图中定义的是计算机专业学生 2008 年 10 月 10 日前的借阅图书情况。
分析:该例可以直接对表进行查询,建立视图,也可以对视图进行查询建立视图。
CREATE VIEW CS_VIEW_081010 AS SELECT *
FROM CS_VIEW
WHERE 借书时间<='2008-10-10' ;
定义基本表时,为了减少数据库中的冗余数据,表中只存放基本数据,由基本数据经过 各种计算派生出的数据一般是不存储的。由于视图中的数据并不实际存储,所以定义视图时可 以根据应用的需要设置一些派生属性列。这些派生属性由于在基本表中并不实际存在,所以有 时也称他们为虚拟列,带虚拟列的视图我们称为带表达式的视图。
【例3-63】定义学生所借图书总价值的视图 TOTAL_PRICE,包括该学生的借书证号、姓 名和总价值。
CREATE VIEW TOTAL_PRICE (借书证号, 姓名, 总价值) AS SELECT BORROW.借书证号, 姓名, SUM(价格) FROM STUDENT,BOOK,BORROW
WHERE STUDENT.借书证号= BORROW.借书证号 AND BOOROW.ISBN=BOOK.ISBN GROUP BY BORROW.借书证号;
3.5.2 查询视图
视图定义后,用户就可以像查询基本表一样查询视图了。DBMS 在执行对视图的查询时,
首先进行有效性检查,检查查询涉及的表、视图等是否在数据库中存在,如果存在,则从数据 字典中取出查询涉及的视图的定义,把定义中的子查询和用户对视图的查询结合起来,转换成 等价的对基本表的查询,然后再执行转换以后的查询。将对视图的查询转换为对基本表的查询
过程称为视图的消解(View Resolution)。
【例3-64】查询计算机学院 2008 年 12 月 30 日借书的学生的借书证号、姓名和 ISBN。
SELECT 借书证号,姓名, ISBN FROM CS_VIEW
WHERE 借书时间= '2008-12-30';
DBMS 在执行此查询时,首先进行有效性检查,然后从数据字典中取出 CS_VIEW 视图的 定义:
CREATE VIEW CS_VIEW
AS SELECT STUDENT.借书证号,姓名,性别,ISBN,借书时间 FROM STUDENT,BORROW
WHERE STUDENT.借书证号= BORROW.借书证号 AND 专业名='计算机' WITH CHECK OPTION ;
再将二者进行合并消解,转换为对基本表的查询:
SELECT STUDENT.借书证号,姓名, ISBN, FROM STUDENT,BORROW
WHERE STUDENT. 借 书 证 号 = BORROW. 借 书 证 号 AND 专 业 名 =' 计 算 机 ' AND 借 书 时 间 = '2008-12-30';
一般来说,DBMS 都可以将对视图的查询正确转换为对基本表的视图,但是,当对有些 视图进行查询时,可能会出现语法错误。
【例3-65】查询学生所借图书的总价值超过 800 元的学生的借书证号、姓名和总价值。
SELECT 借书证号, 姓名, 总价值 FROM TOTAL_PRICE
WHERE 总价值>800;
将该查询与对视图TOTAL_PRICE 的定义结合起来,消解得到的查询语句为:
SELECT BORROW.借书证号, 姓名, SUM(价格) FROM STUDENT,BOOK,BORROW
WHERE STUDENT.借书证号= BORROW.借书证号
AND BOOROW.ISBN=BOOK.ISBN AND SUM(价格)>800 GROUP BY BORROW.借书证号;
显然,转换为对基本表的查询语句是错误的,因为 WHERE 子句中不能用聚集函数作为 条件表达式,正确的查询语句应该为:
SELECT BORROW.借书证号, 姓名, SUM(价格) FROM STUDENT,BOOK,BORROW
WHERE STUDENT.借书证号= BORROW.借书证号 AND BOOROW.ISBN=BOOK.ISBN GROUP BY BORROW.借书证号 HAVING SUM(价格)>800;
因此,当视图的定义中出现了聚集函数所生成的属性列时,如果要对该视图进行有条件限 制的查询,应该直接对基本表进行查询。
3.5.3 更新视图
更新视图包括插入(INSERT)、删除(DELETE)和修改(UPDATE)三类操作,对视图 的更新最终要转换为对基本表的更新。但并非所有的视图都是可更新的。那么到底什么样的视 图是可更新的?若一个视图是从单个基本表导出的,并且只是去掉了某些行和列(不包括关键
更新视图包括插入(INSERT)、删除(DELETE)和修改(UPDATE)三类操作,对视图 的更新最终要转换为对基本表的更新。但并非所有的视图都是可更新的。那么到底什么样的视 图是可更新的?若一个视图是从单个基本表导出的,并且只是去掉了某些行和列(不包括关键