瑞星卡卡安全论坛
斧子 - 2006-2-11 18:21:00
第二周概貌
这一周都讲些什么
在第一周我们讲了使用SELECT 语句进行SQL 的最基本的查询从最简单的SELECT
语句开始我们学习了如何从数据库中取得数据然后我们学习了SQL 中的函数它们在
的用处很大例如在转换数据的格式或财务领域然后你很快就学到了用不同的方法从数
据库中取得数据子句如WHERE ORDER BY 和GROUP BY 允许你对查询进行定制以
返回有特定要求的数据记录你学习了归并操作以从不同的表中返回数据当你需要运行
多个查询且每个查询都需要前一个查询返回的内容时子查询是特别有用处的
在第二周我们将进一步地学习SQL 的使用
l 第8 天教你如何修改数据库中的数据你也许很害怕向数据库中录入数据但是
手工输入数据并不总是必须的现代的数据库系统大多都支持你从其它的数据库
格式中导入或导出数据此外SQL 还提供了几个很有用的语句使你可以熟练地
操纵数据库中的数据
l 第9 天你将学习如何建立和维护数据库中的表你也将学习如何建立数据库和管
理数据库的磁盘空间
l 第10 天将学习如何建立维护使用数据库的视图和索引
l 第11 天将涉及事务处理对数据库进行处理以及撤消对它的改动它对于在线事
务处理程序非常有用
l 第12 天的重点是数据库的安全性拥有数据库安全性知识可以让你更有效地管理
数据库
l 第13 天将学习如何在大型的应用程序中使用SQL 内嵌型SQL 常常运行于宿主
语言如C 或COBOL 上此外开放数据联接ODBC 可以让你在应用程序中
写出在通过数据库驱动在不同的数据库系统上运行的代码也将会提到一些SQL
的高级特性
l 在第14 天将会讨论如何使用动态SQL 并用几个例子来演示如何在应用程序中
使用SQL
斧子 - 2006-2-11 18:22:00
第八天操作数据
目标
今天我们来讨论一下数据操作问题在今天中我们将学习以下内容
l 如何使用INSERT UPDATE 和DELETE 来处理数据
l 在操作数据时使用WHERE 子句的重要性
l 从外部数据源中导入和导出数据的基本方法
斧子 - 2006-2-11 18:23:00
数据操作语句
到现在为止我们已经学习了从数据库出取得数据的每一种可能的操作当获得数据以
后你可以在应用程序中使用或编辑它在第一周主要讨论获得数据但是可能你会对
如何向数据库中输入数据感兴趣你也可能会很想知道如何来编辑数据今天我们将讨
论三个关于如何对数据库中的表中的数据进行操作的三条语句这三条语句是
INSERT 语句
UPDATE语句
DELETE 语句
在过去你也许使用过基于PC 机的数据库系统如ACCESS dBASE IV 和FOXPRO
这些产品提供了很好的输入编辑和删除数据的工具这就是SQL 为什么提供了对数据进
行编辑的基本语句可又允许用户使用应用程序自带的工具进行编辑的原因SQL 的程序员
应该具有将数据送入数据库中的能力此外大型的数据库系统常常不能按照数据库设计
和编程人员的意图来进行设计因为这些数据库系统是为大容量和多用户环境准备的所
以它的设计重点放在了如何优化查询和数据引擎上了
大多数商业化的数据库系统都提供了导入导出数据的工具数据被存储在有分隔符的
文本文件之中格式化的文本文件常常存储着与表相关的信息相关的工具如ORACLE 的
SQL*Loader SQL Server's bcp bulk copy 以Microsoft Acces 的导入和导出数据的工具都
将在今天提到
注今天的例子是用Personal Oracle7 做的请注意它与其它的命令解释器在语句上和数据
返回的形式上的不同之处
斧子 - 2006-2-11 18:23:00
插入语句
INSERT 语句允许你向数据库中输入数据它有两种写法
INSERT VALUES 和INSERT SELECT
斧子 - 2006-2-11 18:23:00
INSERT VALUES 语句
该语句每次向表中输入一条记录如何操作的规模小只有几条语句需要输入时它是
非常有用的该语句的语法形式如下
SYNTAX
INSERT INTO table_name (col1, col2...) VALUES (value1, value2...)
该语句的作用是向表中加以一个新的记录其数值为你所指定的数值使用该语句向
表中插入数据时你必须遵循以下三条规则
l 你所要插入的数值与它所对应的字段必须具有相同的数据类型
l 数据的长度必须小于字段的长度例如你不能向一个长40 个字符的字段中插入
一个长80 个字符的字符串
l 插入的数值列表必须与字段的列表相对应也就是说第一个数值在第一个字段
第二个数值在第二个字段
斧子 - 2006-2-11 18:23:00
例8.1:
假定你有一个COLLECTION 的表中存储着你所收集的材料你可以用下边的语句来
查看其中的内容
INPUT
SQL> SELECT * FROM COLLECTION
OUTPUT
ITEM WORTH REMARKS
NBA ALL STAR CARDS 300 SOME STILL IN BIKE SPOKES
MALIBU BARBIE 150 TAN NEEDS WORK
STAR WARS GLASS 5.5 HANDLE CHIPPED
LOCK OF SPOUSES HAIR 1 HASN'T NOTICED BALD SPOT YET
如果你想向表中加入一个新记录你可以像这样写
SQL 21 日自学通(V1.0) 翻译人笨猪
160
INPUTOUTPUT
SQL> INSERT INTO COLLECTION (ITEM, WORTH, REMARKS)
VALUES('SUPERMANS CAPE', 250.00, 'TUGGED ON IT')
1 row created.
你可以用一个简单的SELECT 语句来验证插入的结果
INPUT/OUTPUT
SQL>SELECT * FROM COLLECTION
ITEM WORTH REMARKS
NBA ALL STAR CARDS 300 SOME STILL IN BIKE SPOKES
MALIBU BARBIE 150 TAN NEEDS WORK
STAR WARS GLASS 5.5 HANDLE CHIPPED
LOCK OF SPOUSES HAIR 1 HASN'T NOTICED BALD SPOT YET
SUPERMANS CAPE 250 TUGGED ON IT
分析
INSERT 语句并不需要列的名字如果列的名字没有给出SQL 会把数据添入对应的
列号中也就是说SQL 会把第一个值插入到第一列中把第二个值插入到第二列中依
此类推
斧子 - 2006-2-11 18:24:00
例8.2
下边的语句将会像例8.1 中的表中插入数值
INPUT
SQL>INSERT INTO COLLECTION VALUES
2 ('STRING',1000.00,'SOME DAY IT WILL BE VALUABLE');
1 row created
分析
为了表明它与例8.1 的效果是相同的你可以用下边的例子来对其进行验证
INPUT
SQL> SELECT * FROM COLLECTION;
OUTPUT
ITEM WORTH REMARKS
NBA ALL STAR CARDS 300 SOME STILL IN BIKE SPOKES
MALIBU BARBIE 150 TAN NEEDS WORK
SQL 21 日自学通(V1.0) 翻译人笨猪
161
ITEM WORTH REMARKS
STAR WARS GLASS 5.5 HANDLE CHIPPED
LOCK OF SPOUSES HAIR 1 HASN'T NOTICED BALD SPOT YET
SUPERMANS CAPE 250 TUGGED ON IT
STRING 1000 SOME DAY IT WILL BE VALUABLE
斧子 - 2006-2-11 18:24:00
插入空值
在第几天的建立和操作表中你将会学到如何使用SQL 的CREATE TABLE 语句来
创建一个表现在你需要知道的是当一个列被创建以后它可能一定的规则限制其中之
一就是它应该或不应该包含空值的存在空值的意思就是该处数值为空但不是零—
— 这属于整数范畴或是空格— — 这属于字符串范畴而是说在空值处根本就没有数据存
在如果列被定义为NOT NULL 这时列中不允许有空值存在则当你使用INSERT 语
句时必须在此列插入一个数值如果你违反了这个规则那么你将收到一个错误的信息
警告你可以在对应的空值列规则上不允许为空值插入空格它不会被看为空值而
且看起来该处并没有数据
INPUT
SQL> insert into collection values
2 ('SPORES MILDEW FUNGUS', 50.00, ' ');
OUTPUT
1 row inserted.
分析
在使用空格来代替空值以后你可以在选择语句中使用空格
INPUT/OUTPUT
SQL> select * from collection
2 where remarks = ' ';
ITEM WORTH REMARKS
SPORES MILDEW FUNGUS 50.00
分析
返回的结果就好像在那里有一个空值一样只从输出上区别这里是空格还是空值是不
太可能的
SQL 21 日自学通(V1.0) 翻译人笨猪
162
如果REMARKS 列被定义为不允许空值那么当输入下边的语句
INPUT/OUTPUT
SQL> INSERT INTO COLLECTION
2 VALUES('SPORES MILDEW FUNGUS',50.00,NULL);
你将会得到一个错误信息
INSERT INTO COLLECTION
*
ERROR at line 1:
ORA-01400: mandatory (NOT NULL) column is missing or NULL during insert
注请注意语法数字和空值不需要引号而字符型数据则需要引号
斧子 - 2006-2-11 18:25:00
插入唯一值
在许多数据库管理系统中都允许你建立一个具有唯一值属性的列这个属性的意思就
是在当前的表中当前列的内容不得出现重复这个属性在当向一个已有的表中插入或更新
数据时可能会导致问题的产生见下例
INPUT
SQL> INSERT INTO COLLECTION VALUES('STRING', 50, 'MORE STRING');
OUTPUT
INSERT INTO COLLECTION VALUES('STRING', 50, 'MORE STRING')
*
ERROR at line 1:
ORA-00001: unique constraint (PERKINS.UNQ_COLLECTION_ITEM) violated
分析
在本例中你试图在COLLECTION 表的ITEM 列中插入另外一个叫STRING 的项目
由于ITEM 列已经被定义为一个唯一的值所以返回了一个错误结果对于这个问题ANSI
SQL 没有提供解决方法但许多商业化的解释器会对此进行扩充如下例
IF NOT EXISTS (SELECT * FROM COLLECTION WHERE NAME = 'STRING'
INSERT INTO COLLECTION VALUES('STRING', 50, 'MORE STRING')
这一例子在Sybase 系统中是支持的
SQL 21 日自学通(V1.0) 翻译人笨猪
163
一个正当的标准化的表中应该有一个唯一值列或关键字列这一字段在归并表格的
时候非常有用如果你使用索引的话它也可以大副度地提高你查询的速度见第10 天创
建视图和索引
注下边的这个插入语句将会向表中插入一个新的雇员
SQL> insert into employee_tbl values
('300500177', 'SMITHH', 'JOHN')
在按下回车键以后你发现你把SMITH 拼错了别担心你可以使用ROLLBACK 命
令来回溯操作而数据则并不会被插入关于ROLLBACK 语句的详细使用方法请参见第
11 天的事务处理控制
斧子 - 2006-2-11 18:25:00
INSERT SELECT 语句
INSERT VALUE 语句在向表中插入几个数据的时候非常有用但显然这是不够的如
果你想向表中插入25,000 行数据时怎么办在这种情况下INSERT SELECT 语句就非常有
效它允许程序员拷贝一个或一组表的信息到另外一个表中你可以在下边这几种情况下
使用该语句需要查询的表经常产生利润的增加需要查询的表可以从多个数据库或表中
获得外部数据由于多个表的查询要比单一表的查询速度慢得多因此对单个表的查询速
度要远远高于复杂而缓慢的多个表查询在服务器/客户机系统上需要查询的表的数据经常
存储在客户机上以减少网络中的数据传输速度
见下例
INPUT
SQL> insert into tmp_tbl
2 select * from table;
OUTPUT
19,999 rows inserted.
分析
你可以将所有的数据都插入到一个临时表中
注并不是所有的数据库管理系统都支持临时表请检查你的数据库系统的文档看看它
是否支持临时表在第14 天中你将会知道对于它的更详细的内容
INSERT SELECT 语句的语法格式如下
SQL 21 日自学通(V1.0) 翻译人笨猪
164
语法
INSERT INTO table_name (col1, col2...)
SELECT col1, col2... FROM tablename WHERE search_condition
本质上来说它是将一个SELECT 语句的输出结果在输入到另一个表格中去在INSERT
VALUE 中的规则也适用于INSERT SELECT 语句如果想把表COLLECTION 中的内容复
制到另一个叫INVENTORY 的表中去你可以使用例8.3 中的语句
例8.3
本例将创建一个叫INVENTORY 的表
INPUT
SQL> CREATE TABLE INVENTORY
2 (ITEM CHAR(20),
3 COST NUMBER,
4 ROOM CHAR(20),
5 REMARKS CHAR(40));
OUTPUT
Table created.
下边的语句将向表中插入COLLECTION 表中的数据
INPUT/OUTPUT
SQL> INSERT INTO INVENTORY (ITEM, COST, REMARKS)
2 SELECT ITEM, WORTH, REMARKS
3 FROM COLLECTION;
6 rows created.
你可以使用SELECT 语句来检验INSERT 的结果
INPUT/OUTPUT
SQL> SELECT * FROM INVENTORY;
ITEM COSTROOM REMARKS
NBA ALL STAR CARDS 300 SOME STILL IN BIKE SPOKES
MALIBU BARBIE 150 TAN NEEDS WORK
STAR WARS GLASS 5.5 HANDLE CHIPPED
LOCK OF SPOUSES HAIR 1 HASN'T NOTICED BALD SPOT YET
SUPERMANS CAPE 250 TUGGED ON IT
SQL 21 日自学通(V1.0) 翻译人笨猪
165
ITEM COSTROOM REMARKS
STRING 1000 SOME DAY IT WILL BE VALUABLE
注数据已经出现在表中了可是在你使用COMMIT 语句之前它并不会真正生效事务
处理工作可以由COMMIT 确认或只是简单地放弃关于COMMIT 的详细内容可见第
11 天
分析
你已经成功了虽然有些费力但是你已经将COLLECTION 中的数据复制到了
INVERTORY 表中
INSERT SELECT 语句要求你遵循如下规则
l SELECT 语句不能从被插入数据的表中选择行
l INSERT INTO 中的列数必须与SELECT 语句返回的列数相等
l INSERT INTO 中的数据类型要与SELECT 语句返回的数据类型相同
INSERT SELECT 语句的另外一个用处是当你需要对表进行重新定义时对表进行备份
这时需要你通过选择原始表中的所有数据并将其插入到一个临时表中来完成例如
SQL> insert into copy_table
2 select * from original_table;
然后你就可以放心地对原始表进行变更了
注在今天的晚些时候你将会学习如何向一个表中导入其它数据库中的数据几乎每一种
商用的数据库都有它们自己的数据存储格式编程人员经常需要对其进行格式转换
你将学习有关这方法的通用方法
斧子 - 2006-2-11 18:25:00
UPDATE 语句
该语句的作用是将已存在的记录的内容改变语法格式如下
SYNTAX
UPDATE table_name SET columnname1 = value1 [, columname2 = value2]...
WHERE search_condition
UPDATE 语句首先要检查WHERE 子句对于符合WHERE 子句条件的记录将会用给
定的数据进行更新
斧子 - 2006-2-11 18:25:00
例8.4
INPUT
SQL> UPDATE COLLECTION SET WORTH = 900 WHERE ITEM = 'STRING';
OUTPUT
1 row updated.
下边的查询可以用来验证确实已经进行了更新操作
INPUT/OUTPUT
SQL> SELECT * FROM COLLECTION WHERE ITEM = 'STRING'
ITEM WORTH REMARKS
STRING 900 SOME DAY IT WILL BE VALUABLE
下边是一个对多个记录进行更新的例子
INPUT/OUTPUT
SQL> update collection set worth = 900, item = ball where item = 'STRING';
1 row updated.
注你所使用的解释器的对多个记录进行更新的语法可能会与这里给出的并不相同
注注意在900 上没有加引号因为它是数值类型而在STRING 上则有引号因
为它是字符串
斧子 - 2006-2-11 18:26:00
例8.5
如果在UPDATE 语句中省略了WHERE 子句那么给定表中的所有记录都会被更新
INPUT/OUTPUT
SQL> UPDATE COLLECTION SET WORTH = 555;
6 rows updated.
下边的SELECT 查询表明了表中的所有记录都已经被更新了
INPUT/OUTPUT
SQL> SELECT * FROM COLLECTION
ITEM WORTH REMARKS
NBA ALL STAR CARDS 555 SOME STILL IN BIKE SPOKES
MALIBU BARBIE 555 TAN NEEDS WORK
STAR WARS GLASS 555 HANDLE CHIPPED
SQL 21 日自学通(V1.0) 翻译人笨猪
167
ITEM WORTH REMARKS
LOCK OF SPOUSES HAIR 555 HASN'T NOTICED BALD SPOT YET
SUPERMANS CAPE 555 TUGGED ON IT
STRING 555 SOME DAY IT WILL BE VALUABLE
当然你也应该检查一下它是否也对具有唯一值属性的列进行了更新操作
警告如果你在UPDATE 语句中没有使用WHERE 子句那么所有给定表中的记录都会被
更新
一些数据库管理系统对标准的UPDATE语句进行了扩展SQL SERVER 的Transact-SQL
就是它们中的一个例子它允许使用FROM 子句实现对给定表的记录用其它表中的数据来
进行更新操作其语法表达如下
SYNTAX
UPDATE table_name SET columnname1 = value1 [, columname2 = value2]...
FROM table_list WHERE search_condition
斧子 - 2006-2-11 18:26:00
例8.6
这是一个实例
INPUT
SQL> UPDATE COLLECTION SET WORTH = WORTH * 0.005
INPUT/OUTPUT
SQL> SELECT * FROM COLLECTION
ITEM WORTH REMARKS
NBA ALL STAR CARDS 2.775 SOME STILL IN BIKE SPOKES
MALIBU BARBIE 2.775 TAN NEEDS WORK
STAR WARS GLASS 2.775 HANDLE CHIPPED
LOCK OF SPOUSES HAIR 2.775 HASN'T NOTICED BALD SPOT YET
SUPERMANS CAPE 2.775 TUGGED ON IT
STRING 2.775 SOME DAY IT WILL BE VALUABLE
分析
该语法在当给定表需要更新的内容源自于其它多个表的时候非常有用切记该语法不
是标准语法在使用它之前请先查看一下你所使用的数据库的文档看一看它是否为你的数
据库系统所支持
UPDATE 语句也可以用一个数学运算式的结果来对给定数据进行更新操作当使用这
项技术时必须注意你所使用的表达式结果与需要更新的数据字段为同一种数据类型而
SQL 21 日自学通(V1.0) 翻译人笨猪
168
且其长度也要与被更新字段的定义长度相符
当使用计算值时可能会有两个问题产生截断和溢出例如当将一个小数转换为整数
时可能会有截断的情况产生而当计算的结果超过了该字段的定义数据长度时会导致溢出
这会使你的数据库返回一个错误
注一些数据库系统可以为你处理溢出问题ORACLE 7 可以在这时将其转成指数形式以
避免错误但是你要清楚在使用数据类型时这种错误存在的可能性
技巧如果在你更新列的以后发现了错误你可以使用ROLLBACK 语句来取消更新操作
就像你对INSERT 所做的那样关于该命令在第11 天会有更多的介绍
斧子 - 2006-2-11 18:26:00
DELETE 语句
与向数据库中加入数据相对应你可能需要删除数据库中的数据DELETE 语句的语
法格式如下
SYNTAX
DELETE FROM tablename WHERE condition
对于DELETE 命令你需要注意的第一件事就是它不会出现确认提示而用户似乎已经
习惯于确认提示了举例来说当我们在操作系统中删除了某个文件或目录时Are you sure?
(Y/N)经常会在命令执行之前出现在使用SQL 时当你告诉DBMS 从表中删除一组记录
时它会执行你的命令而不提问也就是说当你用SQL 的DELETE 命令删除记录时
它确实已经执行了删除操作
在第11 天中我们将会学习到事务处理控制事务控制是一种数据库处理机制它允许
编程人员确认或撤消对数据库的改变该操作对于在线事务处理程序中采用批处理方式对
数据库进行改动时非常有效然而如果同一时间又有其他的用户也在进行数据修改操作时
将会导致引用完整性错误现在假设不存在事务处理机制
注对于一些解释器例如ORACLE 当你在即出SQL 的时候会自动地调用确认操作
通过DELETE 语句和WHERE 子句DELETE 语句可以完成下边的工作
l 删除单一的行
l 删除多个行
l 删除所有的行
SQL 21 日自学通(V1.0) 翻译人笨猪
169
l 什么也不删除
在使用DELETE 语句时需要注意以下几点
l DELETE 不能删除个别的字段它对于给定表只能整个记录整个记录地删除
l 与INSERT 和UPDATE 一样删除一个表中的记录可能会导致与其它表的引
用完整性问题当对数据库进行修改时一定在头脑中有这个概念
l DELETE 语句只会删除记录不会删除表如果要删除表需使用DROP TABLE
命令参见第9 天
斧子 - 2006-2-11 18:27:00
例8.7
下例显示了如何删除COLLECTION 表中的WORTH小于275 的所有记录
INPUT
SQL> DELETE FROM COLLECTION WHERE WORTH < 275
4 rows deleted.
之后表的内容如下
INPUT/OUTPUT
SQL> SELECT * FROM COLLECTION
ITEM WORTH REMARKS
NBA ALL STAR CARDS 300 SOME STILL IN BIKE SPOKES
STRING 1000 SOME DAY IT WILL BE VALUABLE
注与UPDATE 语句一样如果你省略了WHERE 子句那么表中的所有记录都会被删除
例8.8 中则使用了三种数据操作语句来完成一个数据操作过程
斧子 - 2006-2-11 18:27:00
例8.8
INPUT
SQL> INSERT INTO COLLECTION VALUES('CHIA PET', 5,'WEDDING GIFT')
OUTPUT
1 row created.
INPUT
SQL> INSERT INTO COLLECTION
2 VALUES('TRS MODEL III', 50, 'FIRST COMPUTER');
OUTPUT
SQL 21 日自学通(V1.0) 翻译人笨猪
170
1 row created.
现在建立一个新表并向其中复制数据
INPUT/OUTPUT
SQL> CREATE TABLE TEMP (NAME CHAR(20), VALUE NUMBER, REMARKS CHAR(40))
Table created.
INPUT/OUTPUT
SQL> INSERT INTO TEMP(NAME, VALUE, REMARKS)
2 SELECT ITEM, WORTH, REMARKS FROM COLLECTION;
4 rows created.
INPUT/OUTPUT
SQL> SELECT * FROM TEMP;
NAME VALUE REMARKS
NBA ALL STAR CARDS 300 SOME STILL IN BIKE SPOKES
STRING 1000 SOME DAY IT WILL BE VALUABLE
CHIA PET 5 WEDDING GIFT
TRS MODEL III 50 FIRST COMPUTER
现在改变其中的数值
INPUT/OUTPUT
SQL> UPDATE TEMP SET VALUE = 100 WHERE NAME = 'TRS MODEL III'
1 row updated.
INPUT/OUTPUT
SQL> UPDATE TEMP SET VALUE = 8 WHERE NAME = 'CHIA PET';
1 row updated.
INPUT/OUTPUT
SQL> SELECT * FROM TEMP;
NAME VALUE REMARKS
NBA ALL STAR CARDS 300 SOME STILL IN BIKE SPOKES
STRING 1000 SOME DAY IT WILL BE VALUABLE
CHIA PET 8 WEDDING GIFT
TRS MODEL III 100 FIRST COMPUTER
然后将这些数据更新回原始表中
SQL 21 日自学通(V1.0) 翻译人笨猪
171
INPUT
INSERT COLLECTION SELECT * FROM TEMP
DROP TABLE TEMP
分析
关于CREATE TABLE 和DROP TABLE 语句将在第9 天作详细讨论现在这些语句
的作用基本上与它们的名字是一样的CREATE TABLE 会按照你给的格式建立一个新表
而DROP TABLE 则会删除表切记DROP TABLE 会删除中而DELETE 只会删除表中的记
录
为了验证你的工作你可以选出COLLECTION 表中的内容你会看到你改动后的结
果
INPUT/OUTPUT
SQL> SELECT * FROM COLLECTION;
NAME VALUE REMARKS
NBA ALL STAR CARDS 300 SOME STILL IN BIKE SPOKES
STRING 1000 SOME DAY IT WILL BE VALUABLE
CHIA PET 8 WEDDING GIFT
TRS MODEL III 100 FIRST COMPUTER
分析
上边的例子使用了所有的操作数据的三个语句INSERT UPDATE 和DELETE 来对
一个表完成一组操作DELETE 是这三个语句中最容易使用的
警告切记对数据的操作可能会导致引用完整性问题你要认真地检查数据库中所有表的
所有记录以确保正确无误
从外部数据源中导入和导出数据
INSERT UPDATE和DELETE 语句对于数据库程序而言是非常有用的它与SELECT
语句一起为你将要进行的其它数据操作奠定了基础然而SQL 作为一种语言并不提供从
外部数据源中导入和导出数据的方法例如以前你的办公室用了多年的dBASE 数据库
而现在不准备再使用了你的领导想把它转为具有服务器/客户机功能的ORACLE 的
RDBMS 系统显然INSERT UPDATE 和DELETE 语句将会帮助你完成移植工作前提
是你想输入300,000 个记录幸运的是ORACLE 和其他的数据库制造商已经为你提供了完
SQL 21 日自学通(V1.0) 翻译人笨猪
172
成这种任务的工具
几乎所有的数据库系统都可以导入或导出ASCLL 码的文本文件尽管SQL 语言没有
这个功能SQL 不会做得比从一个空数据库开始更好我们可以使用下列产品中的导入和
导出工具它们是Microsoft Access Microsoft 和Sybase SQL Server 以及Personal Oracle7
Microsoft Access
Microsoft Access 是一个其于PC 的数据库产品它具有许多关系数据库管理系统的特
点Microsoft Access 也有强大的报表功能与Visual Basic 类似的宏语言以及从其他的数
据库系统和文本文件中导入或导出数据的能力本部分讲最后边的一种— — 从分界文本文
件中导入或导出数据分界的意思就为每个字段采用特殊的分界符来划定界限一般常用
的分界符是逗号引号和空格
Access 允许你从其他的数据库系统中导入和导出数据这些数据库系统包括dBASE
FoxPro SQL 数据库其中SQL 数据库其实是ODBC 数据链接Microsoft ODBC 将在第
13 天的高级SQL 主题中提到本例中我们讨论文本文件的导入导出过程
在打开Access 数据库以后使用文件|打开选择导出此时将会出现一个对话框
选择文本文件宽度固定选项Access 将会把数据库中的表导出到一个每一个数据类型
都有固定宽度的文本文件中例如如果字符字段宽度为30 就会向文本文件中输出一个长
为30 的字符串如果字符串不足30 就会用空格补足最后会问你文本文件的存放地
点下图显示了导入/导出对话框
SQL 21 日自学通(V1.0) 翻译人笨猪
173
注意在这个对话框中你可以选择文本宽度和字段分隔符最后一步是保存与使用有关
的注释内容注释会存储在数据库的内部
Microsoft and Sybase SQL Server
Microsoft 与Sybase 公司共同开发了新一代的功能强大的服务/客户数据库系统它就
是SQL Server Microsoft 已经同意了在一些平台上开发RDBMS 版本SyBase 则在其他平
台上已经开发了他的数据库版本通常是大型化的虽然在近几年协议有所改变但提到
这个协议可以让我们避免对近几年的数据库系统的版本混淆
SQL Server 提供的数据导入和导出的工具叫BCP BCP 是BULK COPY 的缩写
它的主要内容与ACCESS 的相同但是不幸的是BCP 需要你在提示符下输入命令而不是
在窗口中使用对话框
BCP 可以导出固定宽度的文本文件在SQL Server 中使用它导入文件要比使用ACCESS
直接但ACCESS 更容易使用BCP 使用格式化文本通常扩展名为.FMT 来存储导出
的说明说明文件告诉BCP 导出文件的列名字段宽度以及字段分隔符你可以当数据库
建好后在SQL 内部使用BCP 来建立一个关于数据库结构的说明
Personal Oracle7
Personal Oracle7 允许你导出文本文件文本文件的字段宽度与源库定义的字段宽度相
同使用的工具是SQL*Loader 这个图形工具使用一个控制文件扩展名为.CTL 这个
文件类似与SQL Server 的格式文件.FMT 它的内容是告诉SQL*Loader 数据文件的位
置
SQL*Loader 的界面见下图
SQL 21 日自学通(V1.0) 翻译人笨猪
174
总结
SQL 对于操作数据提供了三条语句
INSERT 语句有二个变体INSERT VALUES 可以插入一个记录而INSERT SELECT
则可以根据给定的一个或多个表来插入一个或多个记录SELECT 语句可以归并多个表
并把归并的结果加入到另外一个表中
UPDATE 语句可以改变符合条件列的值UPDATE 语句可以用计算或表达式的结果作
为需要更新的内容
DELETE 语句是这三个语句中最简单的它会删除符合WHERE 条件的所有记录如
果没有WHERE 子句它会删除表中的所有记录
现代的数据库系统提供了许多的数据库操作的工具其中一些工具可以让开发人员从
外部数据源中导入或导出数据这在当数据库向大系统或小系统上移植时非常有用
Microsoft Access Microsoft 和Sybase 的SQL Server 以及Personal Oracle7 都提供了这样的
移植工具
问与答
问SQL 有导入或导出操作的语句吗
答没有这一操作是解释器的附加功能也就是说ANSI 委员会允许制造商进行他
们认为是需要的工作
问我可以使用INSERT 语句从一个表中抟贝数据到它自身吗我想复制所有记录的
内容而只对其中一个字段的内容作更改
答不能INSERT 语句中的表不能与FROM 中的表相同但是你可以将它复制到
一个临时的表格中这将在第14 天讨论然后对临时表格的内容作修改后再将它复制回
原始表要检查你的表的具有唯一值属性的字段唯一值属性将只允许一个数值在该列中
出现一次
问我注意到了关于INSERT UPDATE 和DELETE 语句的警告是否我可以对我所
犯的错误进行修正如果是的话是那条语句可以完成这种工作
答是的例如你可以使用ROLLBACK 来撤消INSERT UPDATE 或DELETE 的
操作
SQL 21 日自学通(V1.0) 翻译人笨猪
175
但是如果你向表中插入了多个记录后没有发现错误就使用了COMMIT 命令几个星
期后别人发现了错误这时你可能要花上两个星期的时间来对数据库的数据进行逐条的检
查大多数情况下你可能不知道错在哪里所以你只好恢复数据库
校练场
1 下边的语句有什么错误
DELETE COLLECTION
2 下边的语句有什么错误
INSERT INTO COLLECTION SELECT * FROM TABLE_2
3 下边的语句有什么错误
UPDATE COLLECTION ("HONUS WAGNER CARD" 25000, "FOUND IT")
4 如果执行下边的语句会有什么结果
SQL> DELETE * FROM COLLECTION;
5 如果执行下边的语句会有什么结果
SQL> DELETE FROM COLLECTION;
6 如果执行下边的语句会有什么结果
SQL> UPDATE COLLECTION SET WORTH = 555
SET REMARKS = 'UP FROM 525';
7 下边的语句是否会工作
SQL> INSERT INTO COLLECTION SET VALUES = 900 WHERE ITEM = 'STRING'
8 下边的语句是否会工作
SQL> UPDATE COLLECTION SET VALUES = 900 WHERE ITEM = 'STRING'
练习
1 试着向一个表中插入一个不正确的数据类型看一下出错信息然后再插入一
个正确的数据类型
2 试着使用你的数据库系统将某个表导出为其他库格式然后再把它导入熟悉
一下你的数据库系统的导入与导出操作并试着用其它数据库操作导出文件
斧子 - 2006-2-11 18:28:00
第九天创建和操作表
目标
在今天我们将学习创建数据库的知识在第九天我们将学习CREATE DATABSE
CREATE TABLE ALTER TABLE DROP TABLE 以及DROP DATABASE 语句它们被
子统称为数据定义语句与之相对应SELECT UPDATE INSERT DELETE 被称为数
据操作语句到今天结束之时我们将学会以下内容
l 建立关键字段
l 建立一个数据库以及在其中建表
l 表的建立修改与删除
l 向数据库中添加数据
l 修改数据库中的数据
l 删除数据库
从它的语法开始你现在已经知道了许多与SQL 有关的词汇并且知道对SQL 的一部
分已经有了详尽的了解在第二天的查询简介SELECT 语句的使用中我们学会了如
何从数据库中检索数据在第8 天操作数据中我们学习了如何从数据库中添加更新
和删除数据现在在第九天的学习过程中你将会知道数据库是怎么来的为了简单起
见我们忽略了数据库和表的建立过程我们假定这些东西已经存在于你们的系统之上
现在我们来建立它
CREATE 语句的语法可以非常简单或复杂它依据你的数据库管理系统的支持和你对
所要建立的数据库要求而定
注今天的例子使用的是PERSONAL ORACLE 7 请查看你所用的解释器的文档资料以了
解它们与本书中的例子在语法细节上的不同
CREATE DATABASE 语句
在任何数据库项目中管理数据的第一步工作就是建立数据库根据你的要求和你的数
据库管理系统的情况这个工作可以很简单也可以很复杂许多现代的数据库系统包括
SQL 21 日自学通(V1.0) 翻译人笨猪
177
PERSONAL ORACLE 7 都提供了图形工具例你可以通过按鼠标按键来完成数据库的建立
工作这对于节省时间是相当有益处的但是你应该知道SQL 是如何响应鼠标的操作的
典型的数据库创建语句如下
SYNTAX
CREATE DATABASE database_name
由于语法根据系统的不同差别很大所以我们不对CREATE 的语法作更深入的讨论
许多数据库系统甚至不支持数据库的创建命令但是几乎所有的流行了功能强大的关
系型数据库系统都支持它所以我们用创建数据库的选择来代替创建数据库命令的语法讨
论工作
建立数据库时的选项
CREATE DATABASE 语法的差别很大许多SQL 教材中都没有提到它而是直接进行
了CREATE TABLE 语句由于你在创建表之前必须先创建数据库而当一个开发人员在
建立数据库时必须要考虑一些事情第一件事情就是你的权限级别如果你使用的关系型
数据库管理系统支持权限你必须确认你是否具有系统管理设置权限或系统管理员已经允
许你有创建数据库的权限请参见你的数据库文档以获得更多的知识
大多数关系型数据库系统允许你指定数据库的默认大小它通常受你的硬盘容量的限
制你需要清楚你所使用的数据库系统是如何将数据根据你指定的大小存在你的硬盘上的
对空间的管理责任由每个系统管理人员负责所以你的本地的数据库管理人员为你建立一
个测试用的数据库是可能的
不要对CREATE DATABASE 过于关心它非常简单你可以像下边这样来建立一个
名字叫PAYMENTS 的数据库
SYNTAX
SQL> CREATE DATABASE PAYMENTS;
注再一次请你参考你所使用的数据库管理系统的说明书来建立数据库因为CREATE
DATABASE 语句在不同的解释器之间的差别是很大的每一种解释器都有它自己
的一些特点
SQL 21 日自学通(V1.0) 翻译人笨猪
178
设计数据库
设计数据库对于成功的应用来说是非常重要的它将涉及到我们在第一天学习的关系
型数据库理论和标准化数据库理论
标准化过程要求你将数据分解成不同的部分以减少数据的冗余度规划你的数据将是
一个非常复杂的过程有相当多的数据库设计工具可以让你将这一过程变得更合乎逻辑
许多因素会对你设计数据库造成影响如下边的
l 安全问题
l 磁盘的可用空间
l 数据检索及响应的速度
l 数据更新的速度
l 多表归并返回数据的速度
l RDBMS 对临时表的支持
磁盘空间是一个最为重要的因素尽管你可能会认为当磁盘的容量以GB 计时这是不
重要的不要忘记你的数据库越大返回数据库时间就越长如果你的表的设计工作做得
非常糟糕那么你可能会在其中存入许多无用的数据
相反的问题也会产生你可能已经建立了相当多的表所以看起来它们已经非常的合乎
标准化的要求了尽管你的数据库结构非常合理但是在这个数据库上进行的查询工作将
会花费相当多的时间数据库的设计风格有时会因为数据结构并不能清楚地表达设计人的
意图而使维护工作难于进行所以当你在进行代码和数据库的结构设计时将你的数据结构
与你当时的意图进行详细的记录是非常重要的在数据库设计行业中它被称为数据字典
建立数据字典
数据字典是数据库设计人员非常重要的文档资料它可以有以下功能
l 数据库的设计意图谁将会使用它
l 数据库的自身资料用什么创建的数据库数据库的大小是多少日志文件的尺
寸是多少在一些RDBMS 中它存储着数据库的操作信息
l 任何数据库安装或反安装的SQL 原代码记录包括导入/导出数据库的文档资料
记录就像第八天所说的那样
SQL 21 日自学通(V1.0) 翻译人笨猪
179
l 对每一个表的详细描述以及它的最终目的是什么
l 每一个表的内部结构的资料包括表中的所有字段数据类型以及注释情况以及
所有的索引和所有的视图见第10 天创建视图及索引
l 对于每一个存储过程的原代码和触发机制
l 说明数据库是否具有唯一值及非空值约束并说明这些约束是关系型数据库管理
系统强加的还是数据库编制人员设定的以及约束在原代码中的作用范围
许多计算机辅助软件工程工具会在建立数据字典的过程中为你提供帮助例如
MicroSoft Access 在将数据库打包会生成一个文档在文档中对数据库中的每一个细节都进
行了详细的描述在第17 天中的使用SQL 来生成SQL 语句中你了解数据字典的详细
内容
注大多数RDBMS 中都提供了生成数据字典的工具包或有说明来告诉你如何安装它
建立关键字段
在接下来的数据库设计工作中最主要的目标就是建立你的表的结构它包括主关键
字和外关键字其中主关键字用于完成下列目标
保证表中的第一条记录都是唯一的没有一条记录的内容完全与另一条相同至少主
键不能相同
对于一个特定的记录它的所有的列都是必须的列的内容不应出现重复
在第二个目标中如果列的内容在表中从头至尾都没有重复那它就是主关键字外
关键字则是在自己的关系中不唯一标识记录,但在其它关系中可用作对匹配字段链接的一种
关键字下边的例子可以帮助你来区分这两种情况
假定你有三个表BILLS BANK_ACCOUNTS COMPANY 它们的结构如下
Table 9.1. Table structure for the PAYMENTS database.
Bills Bank_Accounts Company
NAME, CHAR(30) ACCOUNT_ID, NUMBER NAME, CHAR(30)
AMOUNT, NUMBER TYPE, CHAR(30) ADDRESS, CHAR(50)
ACCOUNT_ID, NUMBER BALANCE, NUMBER CITY, CHAR(20)
BANK, CHAR(30) STATE, CHAR(2)
在Bills 表中的主关键字段为NAME 字段这一字段是没有重复的因为你只可能有
一个支票的来对应AMOUNT 实际上你可能通过支票号以及日期来保证它的唯一性但
SQL 21 日自学通(V1.0) 翻译人笨猪
180
在这里我们假定NAME 就能做到这一点而ACCOUNT_ID 字段则是BANK_ACCOUNT
的主关键字COMPANY表中的NAME 字段是主关键字
在本例中外部关键字应该是很容易发现的在BILL 表中的ACCOUNT_ID 与
BANK_ACCOUNT 表相关连而NAME 字段则将BILL 表与COMPANY 表相关连如果
这是一个完备的数据库你可能会有更多的表和数据分类例如BANK 字段在
BANK_ACCOUNT 表中可以说明一个银行的信息如地址和电话号码等COMPANY 表可
以与其它表或数据库事件相关连以得到公司及有关产品的信息
斧子 - 2006-2-11 18:28:00
例9.1
同样用BILLS BANK_ACCOUNTS 和COMPANY 表我们来看一个不正确的数据库
设计初学者可能犯的错误就是不会正确地对数据进行尽可能的逻辑分组一个不好的BILL
设计如下
Column Names Comments
NAME CHAR(30) Name of company that bill is owed to
AMOUNT NUMBER Amount of bill in dollars
ACCOUNT_ID NUMBER Bank account number of bill (linked to BANK_ACCOUNTS table)
ADDRESS CHAR(30) Address of company that bill is owed to
CITY CHAR(15) City of company that bill is owed to
STATE CHAR(2) State of company that bill is owed to
结果看上去是正确的但是这只是在数据输入的开始时在几个月以后你已经在NAME
字段中输入了许多公司的账单每当向BILL 表中加入一个新记录的时候公司的
ADDRESS CITY 以及STATE 就有可能出现重复当记录增加到成千上万时重复的数据
也在相应的增加类似的情况也可能在10 20 或30 个表中出现你现在知道数据库标准
化设计的重要性了吧
在你向表中输入数据之前你应该知道如何来创建一个表
CREATE TABLE 语句
建立表的过程比建立数据库的过程更不标准它的基本语法如下
SYNTAX
CREATE TABLE table_name (field1 datatype [ NOT NULL ]
field2 datatype [ NOT NULL ]
SQL 21 日自学通(V1.0) 翻译人笨猪
181
field3 datatype [ NOT NULL ]...)
它的一个简单的例子如下
INPUT/OUTPUT
SQL>CREATE TABLE BILLS (
2 NAME CHAR(30)
3 AMOUNT NUMBER
4 ACCOUNT_ID NUMBER)
Table created.
分析
该语句创建了一个名字叫BILL 的表在BILL 表中有三个字段NAME ACCOUNT
和ACCOUNT_ID 其中NAME 字段为字符类型可以存储长度30 的字符串而AMOUNT
和AMOUNT_ID 则只参存储数字
下边的部分对CREATE TABLE 命令作进一步的解释
表名
当使用PERSONAL ORACLE 来创建一个表的时候对表的命名要遵从几个约束首
先表的名字不得超过30 个字符长由于ORACLE 对大小写不敏感所以在写名字时你
可以根据需要采用大写或小写的方式但是表的第一个字符必须是字母A-Z 其余的字
符则还可以有下划线# $ @ 当然在本工程中表的名字不应该有重复表的名字也
不可以是ORACLE 的保留字如SELECT
注你可以在不同的所有者或工程中使用相同的表的名字但在同一个工程中表的名字必
须保证唯一
FIRST NAME
如果你有过用任何一种语言进编程的经验你会有类似的关于数据类型的概念指定
的字段只能存放特定的数据类型例如字符型字段只能存放字符型数据类型表9.2 显
示了ORACLE 支持的数据类型
ORACLE 所支持的数据类型
SQL 21 日自学通(V1.0) 翻译人笨猪
182
数据类型说明
CHAR 可以存储长度为1~255 个字符的字符串空格会被填充到字符串的右边以保
证其内容满足定义的长度
DATE 包括日期的世纪年月日时分秒
LONG 可以支持长达2G 的字符串见下注
LONG RAW 可以存储长达2G 的二进制内容见下注
NUMBER 零正值或负值的定点或浮点数
RAW 可以存储长不过255 个字节的二进制代码
ROWID 用一个十六进制的数来标明当前行在表内的唯一地址见下注
VARCHAR2 变长的字母或数字长度可以从1 到2000
注LONG 数据类型在其它的数据库系统中常被称为备注类型它主要用于存储大量的可
以在稍后返回的文本内容
LONG RAW 类型在其它数据库系统中常被称为大二进制类型BLOB 它可以用
来存储图形声音视频数据尽管关系型数据库管理系统最初不是为它们而设计的但
是多媒体数据可以存储在BLOB 或LONG RAW 类型的字段内
ROWID 常用在可以将你的表中的每一条记录都加以唯一标识的场合许多关系型
数据库管理系统用COUNTER 如ACCESS 或IDENTITY SQL SERVER 来表达这个
概念
注请检查你的解释器看它们是否对数据类型的支持有所变化
空值属性
SQL 也可以让你鉴别在一个列中是否已经存入的数值NULL 只是一个修饰因为如
果一个字段的内容为NULL 的话实际上是说这个字段中没有东西也没有
在建立表的时候大多数数据库管理系统允许你用NOT NULL 来指明字段是否为非空
属性NOT NULL 的意思就是在当前表的该字段中不能有任何记录存在空值也就是说在
当前表中的该字段的每一个记录中都应该确实存在数值下例给出了NOT NULL 的用法
INPUT
SQL>CREATE TABLE BILLS (
2 NAME CHAR(30) NOT NULL,
SQL 21 日自学通(V1.0) 翻译人笨猪
183
3 AMOUNT NUMBER,
4 ACCOUNT_ID NOT NULL);
分析
在这个例子中如果你想把公司的账转到你自己的名下如果NAME 区和ACCOUNT_ID
区没有内容那么这种存储是没有任何意义的你也许可以在记录中给出账单号但是你
无法收取
下例中的第一个语句插入正确的数据以便为支付JOE 的$25 电脑服务费
INPUT/OUTPUT
SQL> INSERT INTO BILLS VALUES("Joe's Computer Service", 25, 1)
1 row inserted.
INPUT/OUTPUT
SQL> INSERT INTO BILLS VALUES("", 25000, 1)
1 row inserted.
分析
注意在上边的第二个例子中没有给出NAME 的名字你也许会认为这是一件好事
因为没有收款人却收取了25000 元但是我们不这样认为如果NAME 字段在创建时指
定的非空属性那么在第二个例子中就会产生一个错误
唯一属性
你在设计表时的一个目标是要保证在表中有一个列的值是唯一的这列或这个字段被
称为主关键字在一些数据库管理系统中允许你将某一列设成唯一值属性如ORACLE 和
SQL Server 可以让你对一个字段加以唯一值索引见第10 天这一特性可以保证你不
在该字段中插入重复的数值
在选择主关键字段时有几个需要注意的问题我们曾经说过ORACLE 提供了一个
ROWID 字段它对于每一行均会自动递增因此默认情况下它总是一个唯一的数值将
ROWID 字段作为主关键字有许多理由首先对于整数值的归并操作要远远快于对一个
长度为80 个字符的字符串的归并操作因为整数的存储长度小于字符串所以最终归并的
结果集也将小于字符串的归并结果集此外的一个好处是使用ROWID 字段你可以看到表
的组织情况而字符则会产生数字输入的问题例如当一个人输入了111 First Street 而
SQL 21 日自学通(V1.0) 翻译人笨猪
184
另一人输入了111 1st Street 时会有什么情况发生如果又有一个输入了111 1st St.呢在
今天的图形用户界面环境下正确的字符串会被输入到一个列表框中当用户从列表框中
选择的时候代码会将字符串变换成为一个唯一的ID 号并将这个号码存储在数据库中
到现在为止你可以用你在今天所学过的东西来创建一个表了随后我们将在今天使
用这些表所以你应该在表中输入一些数据使用昨天的INSERT 命令可以向表中加入表
9.3 9.4 和9.5 中的数据
INPUT/OUTPUT
SQL>create database PAYMENTS
Statement processed.
SQL>create table BILLS (
2 NAME CHAR(30) NOT NULL,
3 AMOUNT NUMBER,
4 ACCOUNT_ID NUMBER NOT NULL);
Table created.
SQL> create table BANK_ACCOUNTS (
2 ACCOUNT_ID NUMBER NOT NULL,
3 TYPE CHAR(30),
4 BALANCE NUMBER,
5 BANK CHAR(30));
Table created.
SQL> create table COMPANY (
2 NAME CHAR(30) NOT NULL,
3 ADDRESS CHAR(50),
4 CITY CHAR(30),
5 STATE CHAR(2));
Table created.
Table 9.3. Sample data for the BILLS table.
Name Amount Account_ID
Phone Company 125 1
Power Company 75 1
SQL 21 日自学通(V1.0) 翻译人笨猪
185
Name Amount Account_ID
Record Club 25 2
Software Company 250 1
Cable TV Company 35 3
Table 9.4. Sample data for the BANK_ACCOUNTS table.
Account_ID Type Balance Band
1 Checking 500 First Federal
2 Money Market 1200 First Investor's
3 Checking 90 Credit Union
Table 9.5. Sample data for the COMPANY table
Name Address City State
Phone Company 111 1st Street Atlanta GA
Power Company 222 2nd Street Jacksonville FL
Record Club 333 3rd Avenue Los Angeles CA
Software Company 444 4th Drive San Francisco CA
Cable TV Company 555 5th Drive Austin TX
表的存储与尺寸的调整
大多数RDBMS 都设定了表的默认大小和存储的定位如果你没有指定表的大小和存
储大小它就会采用默认值它可能是非常不合适的特别对于大型的表来说更是如此默
认大小根据解释器和不同而不同下边是一个在创建表时使用STORAGE 子句的例子对
于ORACLE 而言
INPUT
SQL> CREATE TABLE TABLENAME
2 (COLUMN1 CHAR NOT NULL,
3 COLUMN2 NUMBER,
4 COLUMN3 DATE)
5 TABLESPACE TABLESPACE NAME
6 STORAGE
7 INITIAL SIZE,
8 NEXT SIZE,
9 MINEXTENTS value,
SQL 21 日自学通(V1.0) 翻译人笨猪
186
10 MAXEXTENTS value,
11 PCTINCREASE value);
OUTPUT
Table created.
分析
在ORACLE 中你可以指定需要存放的表的大小定夺的依据是可用空间的大小经常
是由数据库管理人员来决定INITIAL SIZE 表的初始长度最初的分配空间NEXT SIZE
是指追加的长度MINEXTENTS 和MAXEXTENTS 用于指定表的最小和最大长度
PCTINCREASE 则指明表每次追加的百分比或进行下一次追加
斧子 - 2006-2-11 18:29:00
用一个已经存在的表来建表
CREATE TABLE 是最为通用的建表的方法然而在一些数据库管理系统中提供了一
种可供选择的方法— — 使用已经存在的表中的格式和数据当你对表进行临时改动需要将
数据选出时这种方法是很有用的当你要创建的表与已有的表类似并且其内容也类似时它
也非常有用你不必须重新输入这些信息在ORACLE 中它的语法如下
SYNTAX
CREATE TABLE NEW_TABLE(FIELD1, FIELD2, FIELD3)
AS (SELECT FIELD1, FIELD2, FIELD3
FROM OLD_TABLE <WHERE...>
它的语法允许你建立一个字段类型与已有表中选出的字段类型相同的新表你也可以
对新表中的字段进行重命名
INPUT/OUTPUT
SQL> CREATE TABLE NEW_BILLS(NAME, AMOUNT, ACCOUNT_ID)
AS (SELECT * FROM BILLS WHERE AMOUNT < 50);
Table created.
分析
上边的语句用BILL 表中AMOUNT 小于50 的记录创建了一个新表
在一些数据库系统中你也可以使用下边的语法
SYNTAX
SQL 21 日自学通(V1.0) 翻译人笨猪
187
INSERT NEW_TABLE
SELECT <field1, field2... | *> from OLD_TABLE <WHERE...>
上边的语法格式将会严格地按照原有表的字段格式和数据建立一个新表下边用SQL
Server 的Transact-SQL 来对它进行举例
INPUT
INSERT NEW_BILLS
1> select * from BILLS where AMOUNT < 50
2> go
go 语句在SQL SERVER 中是处理SQL 缓冲区内指令的命令它的作用等同于在
ORACLE 中的分号
ALTER TABLE 语句
没有道理为每件事对你的数据库进行多次的设计但又确实需要对数据库和应用程序
进行改动那么ALTER TABLE 语句可以让数据库的设计者或设计人员在表创建以后修改
它的结构
ALTER TABLE 语句可以帮助你做两件事
l 加入一列到已经存在的表中
l 修改已经存在的表中的某一列
ALTER TABLE 语句的语法如下
SYNTAX
ALTER TABLE table_name <ADD column_name data_type; |
MODIFY column_name data_type;>
下边的命令会将BILL 表中的NAME 字段改为长度40 个字符
INPUT/OUTPUT
SQL> ALTER TABLE BILLS MODIFY NAME CHAR(40);
Table altered.
注你可以增加或减少某一列的长度但是你不能将它减少到使修改后的长度小于其中的
已有数据长度
下边的语句是向NEW_BILLS 表中加入一个新列
SQL 21 日自学通(V1.0) 翻译人笨猪
188
INPUT/OUTPUT
SQL> ALTER TABLE NEW_BILLS
2 ADD COMMENTS CHAR(80);
Table altered.
分析
这条语句会加入一个叫COMMENTS 的长度为80 个字符的字段该字段会加在已有
字段的右边
在使用ALTER TABLE 时会有许多限制你不能用它来对一个数据库增加或删除字段
它可以将一个列由NOT NULL改变为NULL而不必使用其它方法但是如果想把列由NULL
改变为NOT NULL 时则要求指定的字段中不能有NULL 值想把某一列由NOT NULL 改
变为NULL 可以使用下边的语法
SYNTAX
ALTER TABLE table_name MODIFY (column_name data_type NULL)
如果想把一列由NULL 改变为NOT NULL 你必需经过以下步骤
1 确认要改变的列中有没有NULL 值
2 删掉你所发现的任何NULL 值删除该记录更新这一记录等等
3 使用ALTER TABLE 命令
注在一些数据库管理系统中允许使用MODIFY 子句另外一些则不可以而又有
一些在ALTER TABLE 中加入了其它的子句在ORACLE 中你甚至可以修
改表的存储参数请检查你的解释器以找出它对ALTER TABLE 的确实用法
DROP TABLE 语句
SQL 提供了一个可以从数据库去彻底地移去某个表的命令DROP TABLE 可以从数据
库中删除一个指定的表以及与之相关联的索引和视图在第10 天会进行更详细的讨论
一旦这个命令发出以后就没有办法可以彻消它它最常用在你创建一个临时表并且已
经进行完毕了你的全部计划工作的时候DROP TABLE 语句的语法格式如下
SYNTAX
DROP TABLE table_name
下边是如何删掉一个叫NEW_BILLS 表的实例
SQL 21 日自学通(V1.0) 翻译人笨猪
189
INPUT/OUTPUT
SQL>DROP TABLE NEW_BILLS
Table dropped.
分析
请注意系统没有给出你提示该命令不会问你Are you sure? Y/N 但是删除操作
已经执行表已经永远地删除了
警告
如果你执行了
SQL> DROP TABLE NEW_BILLS
如果你想正确地删除一个表那么在删除表的时候最好给出它的所有都所属的数据
库或工程的名字推荐的使用方法如下
SQL> DROP TABLE OWNER.NEW_BILLS
我只所以强调这种使用方法是因为我曾经挽救过一个被错误删除了的表格它被删除
的原因是因为没有准确地给出其所属工程的名字修复那个数据库用了八个小时我们一
直工作到了深夜
DROP DATABASE 语句
一些数据库管理系统也提供了删除数据库DROP DATABASE 的语句它的使用方
法与DROP TABLE 相同语法如下
DROP DATABASE database_name
请不要删掉BILLS 数据库我们在今天的后边还要用它而且在第10 天也要用
注不同的关系数据库解释器提供了不同的删除数据库的方法在数据库被删除以后我
们需要清理掉操作系统用以构建数据库的文件
练习9.2
创建一个数据库并在其中创建一个表试验DROP TABLE 和DROP DATABASE 命令
数据库系统是否会允许你这样做单文件的数据库系统如ACCESS 是不支持这个命令的
数据库包含在一个单一的文件中如果想建立一个数据库你必须用系统提供的菜单选项
如果想删掉它只需简单地从系统中删掉这个文件就可以了
SQL 21 日自学通(V1.0) 翻译人笨猪
190
总结
第9 天讲述了数据处理语言DML 的主要内容具体说来是你学习了五个新的语句
CREATE DATABASE CREATE TABLE ALTER TABLE DROP TABLE DROP DATABASE
在今天的课程中我们也讨论了一个好的数据库设计方案的重要性
当你在创建并设计一个数据库的时候数据字典是一个重要的文档资料字典中有对数
据库的详细的描述包括表字段视图索引存储过程触发机制等等一个完备
的数据字典中应该有对数据库中的每一个内容的详细注释每当你对数据库进行过修改以
后你都应及时的更新数据字典
在使用数据库处理语句时设计一个好的数据库是非常重要的把数据分组逻辑组并
建立主关键字以使其它的逻辑组正确地识别它可以使用外部关键字来指向该表的主关键
字或在该表中用外部关键字与其它的表相关联
我们已经知道了建立数据库语句不是一个数据库系统的必需内容因为不同的数据库
供应商有不同的数据库组织形式每一种解释器都有它们自己的特点和选项从而导致了
建立数据库语句的截然不同只使用CREATE DATABASE database_name 可以在大多数系
统中用默认的参数来创建一个默认的数据库而DROP DATABASE 语句则可以永久地删
除一个数据库
使用CREATE TABLE 语句可以建立一个新的表使用该命令你可以建立字段并定义
它们的数据类型在一些数据库管理系统中你还可以指定字段的其它属性例如是否它可
以接受空值以及它的内容是否在本表中应该是唯一的而ALTER TABLE 语句可以对已存
在的表的结构进行修改DROP TABLE 语句可以永久地删除一个表格
问与答
问为什么CREATE DATABASE语句在不同的数据库中使用方法是不同的
答这是因为不同的数据库系统在建立数据库时的实际过程是不同的基于PC 机的
小型数据库系统通常依赖文件来建立某些应用程序而在大型服务器上运行的分
布式数据库中的需用数据库文件通常是分布在多个磁盘驱动器上的当你的代码
访问数据库的时候运行于电脑上的数据库程序不会像访问你的磁盘上的文件那
样直接更大的数据库系统还要对磁盘的空间进行估算以支持一些特性如安全性
SQL 21 日自学通(V1.0) 翻译人笨猪
191
传输控制以及内嵌于数据库的存储过程当你的程序访问数据库时数据库的服
务程序通常需要对你的请求通常与其它的请求一起经过复杂的中间过程才会
返回数据这一主题将在第3 周讨论现在你应该知道为什么不同的数据库系
统建立和管理数据库的方法不同的
问我能否建立一个临时表并且的工作完成后它会自动地删除
答可以许多数据库管理支持临时表的概念该类型的表可以在你的过程运行结束或你
使用DROP TABLE 语句后删除我们将在第14 天的动态应用SQL 中讨论临时表
问我是否可以用ALTER TABLE 语句来删除一个表
答不行该语句只可以用来增加或修改表中的某一列如果你想删除一列你可以建立
一个新表并将旧表中的数据有选择地复制到新表中然后再删除旧表
校练场
1 ALTER DATABASE 语句经常用在修改已有表的结构上对不对
2 DROP TABLE 语句与DELETE FROM <table_name>的作用是相同的对不对
3 可以使用CREATE TABLE 命令向数据库中加入一个新表对不对
4 为什么下边的语句是错误的
INPUT
CREATE TABLE new_table (
ID NUMBER
FIELD1 char(40)
FIELD2 char(80)
ID char(40)
5 为什么下边的语句是错误的
INPUT
ALTER DATABASE BILLS (
COMPANY char(80))
6 当一个表建立时谁是它的所有者
7 如果字符型列的长度在不断变化如何才能做出最佳的选择
8 表名是否可以重复
SQL 21 日自学通(V1.0) 翻译人笨猪
192
练习
1 用你喜欢的格式向BILLS 数据库中加入两个表名字分别叫BANK 和
ACCOUNT_TYPE BANK 表中应该包含有BANK_ACCOUNT 表中BANK 字段
的信息ACCOUNT_TYPE 表中也应该包含有BANK_ACCOUNT 表中
ACCOUNT_TYPE字段的信息试着尽可以地减少数据的数量
2 使用你已经创建的五个表BILLS BANK_ACCOUNTS COMPANY BANK
ACCOUNT_TYPE 改为表的结构以用整数型字段作为关键字以取代字符型字段
作为关键字
3 使用你所知道的SQL 的归并知识见第6 天表的归并写几个查询来归并BILLS
数据库中的几个表
斧子 - 2006-2-11 18:29:00
第10 天创建视图和索引
目标
今天我们将要讨论的内容对于一些有SQL 有一定了解的程序员或数据库管理人员来说
可能是新东西从第1 天到第8 天我们主要学习了如何使用SQL 在关系数据库中进行基
本的工作在第9 天我们讨论了数据库的设计表的创建以及其它的数据处理语句所有
这些内容的对象表数据库记录字段的共同之处在于— — 它们是存在于磁盘上的
物理对象今天我们来学习SQL 的两个新的特性它允许你以于数据在磁盘上的存储不同
的方式来显示数据这两个特性就是记录和索引到今天的结束你将学习以下内容
l 如何区别索引与视图
l 如何创建视图
l 如何创建索引
l 如何用视图来修改数据
l 索引可以做什么
视图常常被称为虚表它是用CREATE VIEW 语句来建立的在视图建立以后你可以
对视图采用如下命令
l SELECT
l INSERT
l INPUT
l UPDATE
l DELETE
索引是与磁盘上数据的存储方式不同的另外一种组织数据的方法索引的特例是表中
记录依据其在磁盘上的存储位置显示索引可以在表内创建一个列或列的组合当应用索
引以后数据会按照你使用CREATE INDEX 语句所定义的排序方式返回给用户通过对
正确的特定的两个表的归并字段进行索引可以获得明显的好处
注视图与索引是两个完全不同的对象但是它们有一点是相同的它们都与一个表
或数据库相关联尽管每一个对象只能与一个特定的表相关联但它们还是通过对数据的
SQL 21 日自学通(V1.0) 翻译人笨猪
194
预排序和预定义显著地提高了表的工作性能
注在今天的例子中我们使用的是PERSONAL ORACLE 7 对于你使用的解释器请参
阅它的文档与找出它们在语法上的不同之处
使用视图
你可以对封装的复合查询应用视图或虚表当对一组数据建立视图以后你可以像处
理另外一个表一样去处理视图但是在视图中修改数据时要受到一些限制当表中的数
据改变以后你将会在查询视图时发现相应的改变视图并不占用数据库或表的物理空间
CREATE VIEW 和语法如下
SYNTAX
CREATE VIEW <view_name> [(column1, column2...)] AS
SELECT <table_name column_names>
FROM <table_name>
与通常一样语法看起来不太容易使人明白但是对于今天的内容我们有许多例子来
展示视图的用法和优点该命令通知SQL 去创建一个视图用你给出的名字及其列如
果你想指定的话SQL 的SELECT 语句可以判定列所对应的字段及其数据类型没错
就是九天以来你一直使用的SELECT 语句
在你用视图进行任何有用的工作之前你需要对BILLS 数据库再添加一些数据如果
你已经用DROP DATABASE 语句对它进行了试验那么你需要重新建立它数据见表10.1
10.2 和10.3
INPUTOUTPUT
SQL> create database BILLS;
Statement processed.
INPUTOUTPUT
SQL> create table BILLS (
2 NAME CHAR(30) NOT NULL,
3 AMOUNT NUMBER,
4 ACCOUNT_ID NUMBER NOT NULL);
SQL 21 日自学通(V1.0) 翻译人笨猪
195
Table created.
INPUTOUTPUT
SQL> create table BANK_ACCOUNTS (
2 ACCOUNT_ID NUMBER NOT NULL,
3 TYPE CHAR(30),
4 BALANCE NUMBER,
5 BANK CHAR(30));
Table created.
INPUTOUTPUT
SQL> create table COMPANY (
2 NAME CHAR(30) NOT NULL,
3 ADDRESS CHAR(50),
4 CITY CHAR(30),
5 STATE CHAR(2));
Table created.
Table 10.1. Sample data for the BILLS table.
Name Amount Account_ID
Phone Company 125 1
Power Company 75 1
Record Club 25 2
Software Company 250 1
Cable TV Company 35 3
Joe's Car Palace 350 5
S.C. Student Loan 200 6
Florida Water Company 20 1
U-O-Us Insurance Company 125 5
Debtor's Credit Card 35 4
Table 10.2. Sample data for the BANK_ACCOUNTS table.
Account_ID Type Balance Bank
1 Checking 500 FirstFederal
2 MoneyMarket 1200 FirstInvestor's
3 Checking 90 CreditUnion
SQL 21 日自学通(V1.0) 翻译人笨猪
196
Account_ID Type Balance Bank
5 Checking 2500 SecondMutual
6 Business 4500 Fidelity
Table 10.3. Sample data for the COMPANY table.
Name Address City State
Phone Company 111 1st Street Atlanta GA
Power Company 222 2nd Street Jacksonville FL
Record Club 333 3rd Avenue Los Angeles CA
Software Company 444 4th Drive San Francisco CA
Cable TV Company 555 5th Drive Austin TX
Joe's Car Palace 1000 Govt. Blvd Miami FL
S.C. Student Loan 25 College Blvd Columbia SC
Florida Water Company 1883 Hwy 87 Navarre FL
U-O-Us Insurance 295 Beltline Hwy Macon GA
Company
Debtor's Credit Card 115 2nd Avenue Newark NJ
现在你已经成功地使用CREATE DATABASE CREATE TABLE 和INSERT 命令输入
了所有的这些信息现在我们开始对视图作进一步的讨论
简单视图
让我们从最简单的视图开始假设由于一些未知的原因我们需要在BILLS 中创建视
图它看上去与BILLS 表相同但是名字叫DEBTS 不相同语句如下
INPUT
SQL> CREATE VIEW DEBTS AS
SELECT * FROM BILLS;
可以用下边的语句来确认上边的结果
INPUT/OUTPUT
SQL> SELECT * FROM DEBTS;
NAME AMOUNT ACCOUNT_ID
Phone Company 125 1
Power Company 75 1
Record Club 25 2
Software Company 250 1
Cable TV Company 35 3
Joe's Car Palace 350 5
SQL 21 日自学通(V1.0) 翻译人笨猪
197
NAME AMOUNT ACCOUNT_ID
S.C. Student Loan 200 6
Florida Water Company 20 1
U-O-Us Insurance Company 125 5
Debtor's Credit Card 35 4
你甚至可以已经存在的视图来创建一个新的视图当从视图中创建视图时要仔细尽
管操作是可以接受的但是它使得维护工作变得复杂假设你的视图有三级如表的视图
的视图的视图那么当表中的第一级视图被删除时会有什么情况发生另外两个视图会仍
然存在但是在第一个视图恢复之前它们是没有用处的切记当创建一个视图后,它实际
上是一个虚表
INPUT
SQL> CREATE VIEW CREDITCARD_DEBTS AS
2 SELECT * FROM DEBTS
3 WHERE ACCOUNT_ID = 4;
SQL> SELECT * FROM CREDITCARD_DEBTS;
OUTPUT:
NAME AMOUNT ACCOUNT_ID
Debtor's Credit Card 35 4
CREATE VIEW 也允许你从表中选择特定的列到视图中下例是从COMPANY 表中选
择了NAME 和STATE 列
INPUT
SQL> CREATE VIEW COMPANY_INFO (NAME, STATE) AS
2 SELECT * FROM COMPANY;
SQL> SELECT * FROM COMPANY_INFO;
OUTPUT
NAME STATE
Phone Company GA
Power Company FL
Record Club CA
Software Company CA
Cable TV Company TX
Joe's Car Palace FL
SQL 21 日自学通(V1.0) 翻译人笨猪
198
NAME STATE
S.C. Student Loan SC
Florida Water Company FL
U-O-Us Insurance Company GA
Debtor's Credit Card NJ
注用户可以通过创建视图来查询特定的数据如果你的表有50 列且有成千上万个记
录但是你只需要其中两列的话你可以创建视图来选择这两列然后从视图中查询你会
发现查询在数据返回时间上与原来有相当大的不同
斧子 - 2006-2-11 18:30:00
列的重命名
视图继承了已有列的名字此外视图还可以有自己的名字SQL 的CREATE VIEW 允
许你对所选择的列进行重命名它与前边的例子非常相似如果你想把COMPANY 中的
ADDRESS CITY 和STATE 字段组合起来并打印到信封上时该如何做呢请看下边的例
子它使用了SQL 的+操作符将地址字段与逗号和空格组合起来
INPUT
SQL> CREATE VIEW ENVELOPE (COMPANY, MAILING_ADDRESS) AS
2 SELECT NAME, ADDRESS + " " + CITY + ", " + STATE
3 FROM COMPANY;
SQL> SELECT * FROM ENVELOPE
OUTPUT
COMPANY MAILING_ADDRESS
Phone Company 111 1st Street Atlanta, GA
Power Company 222 2nd Street Jacksonville, FL
Record Club 333 3rd Avenue Los Angeles, CA
Software Company 444 4th Drive San Francisco, CA
Cable TV Company 555 5th Drive Austin, TX
Joe's Car Palace 1000 Govt. Blvd Miami, FL
S.C. Student Loan 25 College Blvd. Columbia, SC
Florida Water Company 1883 Hwy. 87 Navarre, FL
U-O-Us Insurance Company 295 Beltline Hwy. Macon, GA
Debtor's Credit Card 115 2nd Avenue Newark, NJ
SQL 21 日自学通(V1.0) 翻译人笨猪
199
分析
当在视图中使用SQL 的计算功能时SQL 会要求你给出一个虚字段的名字这是可以
理解的因为像COUNT(*)或AVG(PAYMENT).是不能作为名字的
注检查你的解释器看它是否支持+操作符
SQL 对视图的处理过程
视图可以以比数据在数据库表中的存储情况更为便捷的方式来返回数据当需要连续
进行几个复合的查询时例如在存储过程和应用程序中时视图也是非常方便的为了进
一步地说明视图和SELECT 语句下边的例子分别使用了SQL 的查询方法和视图方法以
作对比假设你需要经常去运行一个查询例如你需要例行公事地将BILLS 表与
BANK_ACCOUNT 表进行归并以得到支付信息
INPUT
SQL> SELECT BILLS.NAME, BILLS.AMOUNT, BANK_ACCOUNTS.BALANCE
2 BLANCE BANK_ACCOUNTS.BANK BANK FROM BILLS, BANK_ACCOUNTS
3 WHERE BILLS.ACCOUNT_ID = BANK_ACCOUNTS.ACCOUNT_ID;
OUTPUT
BILLS.NAME BILLS.AMOUNT BALANCE BANK
Phone Company 125 500 First Federal
Power Company 75 500 First Federal
Record Club 25 1200 First Investor's
Software Company 250 500 First Federal
Cable TV Company 35 90 Credit Union
Joe's Car Palace 350 2500 Second Mutual
S.C. Student Loan 200 4500 Fidelity
Florida Water Company 20 500 First Federal
U-O-Us Insurance Company 125 2500 Second Mutual
这一过程用视图来表达则语句如下
INPUT/OUTPUT
SQL> CREATE VIEW BILLS_DUE (NAME, AMOUNT, ACCT_BALANCE, BANK) AS
2 SELECT BILLS.NAME, BILLS.AMOUNT, BANK_ACCOUNTS.BALANCE
3 BANK_ACCOUNTS.BANK FROM BILLS, BANK_ACCOUNTS
SQL 21 日自学通(V1.0) 翻译人笨猪
200
4 WHERE BILLS.ACCOUNT_ID = BANK_ACCOUNTS.ACCOUNT_ID
View created.
如果你对BILLS_DUE 视图执行查询是使用了一些条件如下语句所示
INPUT/OUTPUT
SQL> SELECT * FROM BILLS_DUE
2 WHERE ACCT_BALANCE > 500
NAME AMOUNT ACCT_BALANCE BANK
Record Club 25 1200 FirstInvestor's
Joe's Car Palace 350 2500 SecondMutual
S.C. Student Loan 200 4500 Fidelity
U-O-Us Insurance Company 125 2500 SecondMutual
分析
在上述语句中SQL 执行了好几步操作因为BILLS_DUE 是一个视图不是一个真实
的表SQL 首先查找一个名字叫BILLS_DUE 的表但是没有找到SQL 的过程可能会从
系统表中发现BILLS_DUE 原来是一个视图这依据你所使用的数据库而定于是它对视
图进行了诠释并形成了如下的查询语句
SQL> SELECT BILLS.NAME, BILLS.AMOUNT, BANK_ACCOUNTS.BALANCE,
2 BANK_ACCOUNTS.BANK FROM BILLS, BANK_ACCOUNTS
3 WHERE BILLS.ACCOUNT_ID = BANK_ACCOUNTS.ACCOUNT_ID
4 AND BANK_ACCOUNTS.BALANCE > 500;
例10.1
构造一个视图以显示所有需要发送账单的州同时要求显示每个州的账单金额总数和
账单的总数
首先你知道CREATE VIEW 语句看起来应该是下边的样子
CREATE VIEW EXAMPLE (STATE, TOTAL_BILLS, TOTAL_AMOUNT) AS...
现在你必须决定SELECT 语句的内容你要清楚根据需要你要选择STATE 字段并应
该使用SELECT DISTINCT 语法以显示账单需要发送的州例如
INPUT
SQL> SELECT DISTINCT STATE FROM COMPANY;
OUTPUT
STATE GA FL CA TX SC NJ 为节约宽度这里用制表符取代了段落标记
SQL 21 日自学通(V1.0) 翻译人笨猪
201
除了选择州字段以外你还需要知道发往这个州的账单总数因此你需要归并BILLS
表和COMPANY表
INPUT/OUTPUT
SQL> SELECT DISTINCT COMPANY.STATE, COUNT(BILLS.*) FROM BILLS, COMPANY
2 GROUP BY COMPANY.STATE
3 HAVING BILLS.NAME = COMPANY.NAME;
STATE COUNT(BILLS.*)
GA 2
FL 3
CA 2
TX 1
SC 1
NJ 1
现在你已经成功地返回了需要的三分之二的结果你可以用下边的语句来最终结束这
条语句加入SUM 语句以返回每个州的金额总数
INPUT/OUTPUT
SQL> SELECT DISTINCT COMPANY.STATE, COUNT(BILLS.NAME), SUM(BILLS.AMOUNT)
2 FROM BILLS, COMPANY
3 GROUP BY COMPANY.STATE
4 HAVING BILLS.NAME = COMPANY.NAME
STATE COUNT(BILLS.*) SUM(BILLS.AMOUNT)
GA 2 250
FL 3 445
CA 2 275
TX 1 35
SC 1 200
NJ 1 35
最后一步你可以将它与最初的CREATE VIEW 语句组合在一起
INPUT/OUTPUT
SQL> CREATE VIEW EXAMPLE (STATE, TOTAL_BILLS, TOTAL_AMOUNT) AS
2 SELECT DISTINCT COMPANY.STATE, COUNT(BILLS.NAME),SUM(BILLS.AMOUNT)
3 FROM BILLS, COMPANY
SQL 21 日自学通(V1.0) 翻译人笨猪
202
4 GROUP BY COMPANY.STATE
5 HAVING BILLS.NAME = COMPANY.NAME;
INPUT/OUTPUT
SQL> SELECT * FROM EXAMPLE;
STATE TOTAL_BILLS TOTAL_AMOUNT
GA 2 250
FL 3 445
CA 2 275
TX 1 35
SC 1 200
NJ 1 35
上边的例子向你展示了如何设计CREATE VIEW 语句和SELECT 语句SELECT 语句
测试代码的作用在于检查数据的返回结果是不是符合你的要求然后才将其最终组合来创
建一个视图
例10.2
假设你的债权人因为你推迟付款加收10%的服务费而且不幸的是你在这个月的每件
事都需要推迟因此你想看一下需要推迟付款的债主的账号
归并语句在这里是非常简单的因为你不需要使用像SUM 或COUNT 之类的语句
可是你会第一次发现使用视图的好处在视图中你可以将增加的10%的服务费在视图中作
为一个字段由于这一点你可以在视图中使用SELECT 语句来为你计算总计的结果语
句如下
INPUT
SQL> CREATE VIEW LATE_PAYMENT (NAME, NEW_TOTAL, ACCOUNT_TYPE) AS
2 SELECT BILLS.NAME, BILLS.AMOUNT * 1.10, BANK_ACCOUNTS.TYPE
3 FROM BILLS, BANK_ACCOUNTS
4 WHERE BILLS.ACCOUNT_ID = BANK_ACCOUNTS.ACCOUNT_ID;
OUTPUT
View created.
INPUT/OUTPUT
SQL> SELECT * FROM LATE_PAYMENT
SQL 21 日自学通(V1.0) 翻译人笨猪
203
NAME NEW_TOTAL ACCOUNT_TYPE
Phone Company 137.50 Checking
Power Company 82.50 Checking
Record Club 27.50 MoneyMarket
Software Company 275 Checking
Cable TV Company 38.50 Checking
Joe's Car Palace 385 Checking
S.C. Student Loan 220 Business
Florida Water Company 22 Checking
U-O-Us Insurance Company 137.50 Business
Debtor's Credit Card 38.50 Savings
斧子 - 2006-2-11 18:30:00
在SELECT 语句使用约束
在视图的SELECT 语句中使用约束是必然的在使用SELECT 语句中可以应用下边这
两个规则
l 你不能使用UNION 操作
l 你不能使用ORDER BY 子句但是在视图中使用GROUP BY 子句可以有ORDER
BY 子句相同的功能
在视图中修改数据
正如同你所学习过的你可以在数据库的一个或多个表中使用视图你也可以在SQL
和数据库应用程序中使用虚表在使用CREATE VIEW SELECT 创建视图以后你可以用
在第八天操作数据学习过的INSERT UPDATE 和DELETE 语句来更新插入删除
视图中的数据
我们在稍后讨论在视图中操作数据的限制下边的例子显示了如何在视图中操作数据
将例10.2 中的工作继续更新BILLS 表中的那不幸的10%的费用
INPUT/OUTPUT
SQL> CREATE VIEW LATE_PAYMENT AS
2 SELECT * FROM BILLS;
SQL> UPDATE LATE_PAYMENT
2 SET AMOUNT = AMOUNT * 1.10;
SQL 21 日自学通(V1.0) 翻译人笨猪
204
SQL> SELECT * FROM LATE_PAYMENT;
NAME NEW_TOTAL ACCOUNT_ID
Phone Company 137.50 1
Power Company 82.50 1
Record Club 27.50 2
Software Company 275 1
Cable TV Company 38.50 3
Joe's Car Palace 385 5
S.C. Student Loan 220 6
Florida Water Company 22 1
U-O-Us Insurance Company 137.50 5
Debtor's Credit Card 38.50 4
为了验证结果确实已经进行了更新我们在一次在BILLS 表中运行查询
INPUT/OUTPUT
SQL> SELECT * FROM BILLS
NAME NEW_TOTAL ACCOUNT_ID
Phone Company 137.50 1
Power Company 82.50 1
Record Club 27.50 2
Software Company 275 1
Cable TV Company 38.50 3
Joe's Car Palace 385 5
S.C. Student Loan 220 6
Florida Water Company 22 1
U-O-Us Insurance Company 137.50 5
Debtor's Credit Card 38.50 4
现在我们从视图中删除一行
INPUT/OUTPUT
SQL> DELETE FROM LATE_PAYMENT
2 WHERE ACCOUNT_ID = 4;
SQL> SELECT * FROM LATE_PAYMENT;
NAME NEW_TOTAL ACCOUNT_ID
Phone Company 137.50 1
Power Company 82.50 1
Record Club 27.50 2
SQL 21 日自学通(V1.0) 翻译人笨猪
205
Software Company 275 1
Cable TV Company 38.50 3
Joe's Car Palace 385 5
S.C. Student Loan 220 6
Florida Water Company 22 1
U-O-Us Insurance Company 137.50 5
最后一步是测试UPDATE 函数为BILLS 表中所有的NEW_TOTAL 中大于100 的增
加10
INPUT/OUTPUT
SQL> UPDATE LATE_PAYMENT
2 SET NEW_TOTAL = NEW_TOTAL + 10
3 WHERE NEW_TOTAL > 100;
SQL> SELECT * FROM LATE_PAYMENT;
NAME NEW_TOTAL ACCOUNT_ID
Phone Company 147.50 1
Power Company 82.50 1
Record Club 27.50 2
Software Company 285 1
Cable TV Company 38.50 3
Joe's Car Palace 395 5
S.C. Student Loan 230 6
Florida Water Company 22 1
U-O-Us Insurance Company 147.50 5
在视图中修改数据的几个问题
你大概已经看到了视图其实就是一组表的映射所以想要修改下层表的数据并不会
总是像上例那样直接下面给出了你在使用视图进行工作时常用会遇到的限制
l 对于多表视图你不能使用DELETE 语句
l 除非底层表的所有非空列都已经在视图中出现否则你不能使用INSERT 语句
有这个限制的原因是SQL 不知道应该将什么数据插入到NOT COLUMNS 限制列
中没有在视图中出现的
l 如果对一个归并的表格插入或更新记录那么所有被更新的记录必须属于同一个
SQL 21 日自学通(V1.0) 翻译人笨猪
206
物理表
l 如果你在创建视图时使用了DINTINCT 子句那么你就不能插入或更新这个视图
中的记录
l 你不能更新视图中的虚拟列它是用计算字段得到了
通用应用程序的视图
下边有几个视图需要完成的任务
l 提供了用户安全功能
l 可以进行单位换算
l 创建一个新的虚拟表格式
l 简单的结构化复合查询
视图与安全性
尽管我们需要在第12 天的数据库安全中才会完全地讨论数据库的安全性但是在
本题目下我们先来大致谈一谈如何使用视图的安全性功能
所有的关系型数据库在今天都有着完善的内置的安全性特性数据库系统的用户通常
会根据他们所使用的数据库来分成不同的组常用组的类型有数据库管理员database
administrators 数据库开发员database developers 数据录入人员data entry personnel
和大众用户不同的组在使用数据库时有着不同的权限数据库管理员具有系统的完全控
制权限包括更新UPDATE 插入INSERT 删除DELETE 修改ALTER 数
据库的特权而大众用户则只有使用SELECT 语句的权利— — 或许是只有对特定的数据库
使用特定的SELECT 语句的权利
视图通常用在对用户访问数据进行控制的场所例如如果你只想让用户访问BILLS
表中的NAME 字段你需要创建一个名字叫BILLS_NAME 的视图
INPUT/OUTPUT
SQL> CREATE VIEW BILLS_NAME AS SELECT NAME FROM BILLS
具有系统管理员权限的人也可以使用具有公共组SELECT 权限的BILLS_NAME 该
组没有任何对下层BILLS 表的权限如你所料SQL 也提供了可以使用的数据安全语句
现在你要知道的是视图对于实现数据库的安全有相当大的用处
SQL 21 日自学通(V1.0) 翻译人笨猪
207
在单位换算中使用视图
视图在你提供给用户的数据与数据库中的真实数据不同时也相当有用例如如果
AMOUNT 字段实际上存储于美国加拿大的用户不想频繁地进行美元与加拿大元之间的
转换工作那么你可以创建一个叫CANADA_BILLS 的视图
INPUT/OUTPUT
SQL> CREATE VIEW CANADIAN_BILLS (NAME, CAN_AMOUNT) AS
2 SELECT NAME, AMOUNT / 1.10
3 FROM BILLS
SQL> SELECT * FROM CANADIAN_BILLS
NAME CAN_AMOUNT
Phone Company 125
Power Company 75
Record Club 25
Software Company 250
Cable TV Company 35
Joe's Car Palace 350
S.C . Student Loan 200
Florida Water Company 20
U-O- Us Insurance Company 125
分析
当进行类似这样的单位转换时要注意当计算字段创建一个列时修改底层表的数据时
可能带来的问题与往常一样你应该查看你的数据库系统的相关文档看一看你的系统上
的CREATE VIEW 命令是如何执行了
斧子 - 2006-2-11 18:30:00
在视图中使用简单的结构化复合查询
视图在你需要按次序运行一系列查询以后得到某个结果的情况下也很有用下边的例
子显示了如何在这种情况下使用视图
如果想找出所有发给德克萨斯州的账单金额少于50 美元的银行的名字你可以把这个
问题分解成如下的两个问题
l 得到所有发给德克萨斯州的账单
SQL 21 日自学通(V1.0) 翻译人笨猪
208
l 找出账单中金额小于50 美元的记录
让我们用两个分开的视图BILLS_1 和BILLS_2 来解决这两个问题
INPUT/OUTPUT
SQL> CREATE TABLE BILLS1 AS
2 SELECT * FROM BILLS
3 WHERE AMOUNT < 50;
SQL> CREATE TABLE BILLS2 (NAME, AMOUNT, ACCOUNT_ID) AS
2 SELECT BILLS.* FROM BILLS, COMPANY
3 WHERE BILLS.NAME = COMPANY.NAME AND COMPANY.STATE = "TX";
分析
因为你想找的是所有发给德州的账单和所有账单中小于50 美元的账单你现在可以使
用SQL 中的IN 子句来找出所有在BILLS1 中发往德州的账单这个信息来创建一个名字
叫BILLS3 的视图
INPUT/OUTPUT
SQL> CREATE VIEW BILLS3 AS
2 SELECT * FROM BILLS2 WHERE NAME IN
3 (SELECT * FROM BILLS1);
现在将上述查询与BANK_ACCOUNT 表进行合并以得到最初想要的结果
INPUT/OUTPUT
SQL> CREATE VIEW BANKS_IN_TEXAS (BANK) AS
2 SELECT BANK_ACCOUNTS.BANK
3 FROM BANK_ACCOUNTS, BILLS3
4 WHERE BILLS3.ACCOUNT_ID = BANK_ACCOUNTS.ACCOUNT_ID
SQL> SELECT * FROM BANK_IN_TEXAS;
BANK
Credit Union
分析
如你所见当把一个查询分解成几个视图以后最后的查询就非常简单了当然使
用一个视图也经常是必需的
SQL 21 日自学通(V1.0) 翻译人笨猪
209
删除视图语句
就像每一个CREATE 语句一样CREATE VIEW 语句对应的也与DROP VIEW 语句相
对应其语法形式如下
SQL> DROP VIEW view_name
在使用它的时候需要记住DROP VIEW 命令会使所有与DROP 视图相关联的视图不
能正常运行一些数据库系统甚至会将所有与要DROP 的视图相关联的视图也删除掉在
Personal Oracle7 中如果你将BILLS1 删除那么最终的查询将会返回下边的错误
INPUT/OUTPUT
SQL> DROP VIEW BILLS1;
View dropped.
SQL> SELECT * FROM BANKS_IN_TEXAS;
ERROR at line 1:
ORA-04063: view "PERKINS.BANKS_IN_TEXAS" has errors
注你可以删除一个视图而不影响任何一个真实的表这也就是为什么我们将视图称为虚
表的原因虚体也使用了相同的逻辑
使用索引
使用索引是另外一种让数据提供给用户的形式与它在数据库中不同的方法此外索
引可以让存储于磁盘上的数据进行重新排序这是一些视图不具有的功能
在SQL 中使用索引是其于以下几个原因
l 在使用UNIQUE 关键字时强制性地保证数据的完整性
l 可以容易地用索引字段或其它字段进行排序
l 提高查询的执行速度
什么是索引
可以用两种方法从数据库中获得数据第一种方法常被称为顺序访问方式它需要SQL
检查每一个记录以找到与之相匹配的这种查找的方法效率很低但它是使记录准确定位
的唯一方法回想一下以前图书馆的卡片档案系统假设卡片是按字母的顺序排列的那
SQL 21 日自学通(V1.0) 翻译人笨猪
210
么在将它们抽出来后在放回卡片柜时那么当你来到书柜的旁边以后那么你只能从头开
始然后一张卡片一张卡片地看直到找到你所需要的当然也许你碰巧很快就找到了
现在假设图书管理员将书的标题按字母顺序排列那么通过查看目录中的书的字母顺
序你可以很快地找到你想要的书
进一步设想如果管理员非常勤劳他不但将书按标题进行了排序而且还另外制作了
不同的卡片柜在那个卡片柜中他是按照作者的名字或其他的方式进行排序的那么这对
于你一个图书馆的读者来说检索信息就有了相当大的灵活性而且你只需要很短的时间
就能找到你所需要的内容
在数据库中使用索引可以让SQL 使用直接访问方式SQL 采用树形结构来存储和返回
索引数据用以指示的数据存储在树的最末端也就是叶子它们被称为结点也可以叫
叶子每一个结点中有一个指向其它结点的指针结点左边的值只是它的双亲结点结点
右边的值则是孩子结点或叶子
SQL 将从根结点开始直到找到所需要的数据
注当查询没有使用索引的表时查询通常是全表搜索后才会得到结果全表搜索会让数据
库服务程序遍历过表中的所有记录然后返回给定条件的记录这种方法就好比从图书
馆的第一号书架的第一本书找起直到找到了你所需要的书一样你或许会使用卡片
柜以更快地找到所需的书索引可以让数据库服务程序快速地定位到表中的确定行
幸运的是这个树结构不需要由你来制作你甚至不必去写从数据库的表中存储和读的
过程基本的SQL 索引的语法形式如下
INPUT/OUTPUT
SQL> CREATE INDEX index_name
2 ON table_name(column_name1, [column_name2], ...)
像你以前多次看到的那样索引的语法对于不同的数据库系统差别很大例如CREATE
INDEX 语句在ORACLE7 中的形式如下
SYNTAX
CREATE INDEX [schema.]index
ON { [schema.]table (column [!!under!!ASC|DESC]
[, column [!!under!!ASC|DESC]] ...)
| CLUSTER [schema.]cluster }
SQL 21 日自学通(V1.0) 翻译人笨猪
211
[INITRANS integer] [MAXTRANS integer]
[TABLESPACE tablespace]
[STORAGE storage_clause]
[PCTFREE integer]
[NOSORT]
而它在Sybase SQL Server 中的语法形式则如下
SYNTAX
create [unique] [clustered | nonclustered]
index index_name
on [[database.]owner.]table_name (column_name
[, column_name]...)
[with {fillfactor = x, ignore_dup_key, sorted_data,
[ignore_dup_row | allow_dup_row]}]
[on segment_name]
Informix SQL 解释器的命令形式则如下
SYNTAX
CREATE [UNIQUE | DISTINCT] [CLUSTER] INDEX index_name
ON table_name (column_name [ASC | DESC],
column_name [ASC | DESC]...)
注意到所有这些解释器有几点是相同的它们的基本开始语句都是
CREATE INDEX index_name ON table_name (column_name, ...)
SQL Server 和ORACLE 允许你创建成簇的索引这将在稍后讨论ORACLE 和Informix
允许你指明列名是按升序排列还是按降序排列我们不喜欢听到被打断的声音但是请再
一次参考你的数据库管理系统以得到明确的关于CREATE INDEX 的指示
例如要对BILLS 表中的ACCOUNTID 字段创建索引其CREATE INDEX 语句如下
INPUT
SQL> SELECT * FROM BILLS
OUTPUT
SQL 21 日自学通(V1.0) 翻译人笨猪
212
NAME AMOUNT ACCOUNT_ID
Phone Company 125 1
Power Company 75 1
Record Club 25 2
Software Company 250 1
Cable TV Company 35 3
Joe's Car Palace 350 5
S.C. Student Loan 200 6
Florida Water Company 20 1
U-O-Us Insurance Company 125 5
Debtor's Credit Card 35 4
INPUT/OUTPUT
SQL> CREATE INDEX ID_INDEX ON BILLS( ACCOUNT_ID );
SQL> SELECT * FROM BILLS
NAME AMOUNT ACCOUNT_ID
Phone Company 125 1
Power Company 75 1
Software Company 250 1
Florida Water Company 20 1
Record Club 25 2
Cable TV Company 35 3
Debtor's Credit Card 35 4
Joe's Car Palace 350 5
U-O-Us Insurance Company 125 5
S.C. Student Loan 200 6
直至索引被DROP INDEX 语句删除之前BILLS 表是按照ACCOUNT_ID 的顺序进行
排序的DROP INDEX 语句是非常清楚的
SYNTAX
SQL> DROP INDEX index_name;
当索引被删除以后的结果是什么样呢
INPUT/OUTPUT
SQL> DROP INDEX ID_INDEX
Index dropped.
SQL> SELECT * FROM BILLS
SQL 21 日自学通(V1.0) 翻译人笨猪
213
NAME AMOUNT ACCOUNT_ID
Phone Company 125 1
Power Company 75 1
Record Club 25 2
Software Company 250 1
Cable TV Company 35 3
Joe's Car Palace 350 5
S.C. Student Loan 200 6
Florida Water Company 20 1
U-O-Us Insurance Company 125 5
Debtor's Credit Card 35 4
分析
现在的BILLS 表是它原本的形态使用索引不会对表中的物理存储造成影响
你也许想知道为什么数据库提供了索引而又允许你使用ORDER BY 子句吧
INPUT/OUTPUT
SQL> SELECT * FROM BILLS ORDER BY ACCOUNT_ID;
NAME AMOUNT ACCOUNT_ID
Phone Company 125 1
Power Company 75 1
Software Company 250 1
Florida Water Company 20 1
Record Club 25 2
Cable TV Company 35 3
Debtor's Credit Card 35 4
Joe's Car Palace 350 5
U-O-Us Insurance Company 125 5
S.C. Student Loan 200 6
分析
它与使用ID_INDEX 语句的结果是一样的不同之处在于当你使用ORDER BY 子句
时每次运行它都需要重新进行排序而当你使用索引的时候数据库会建立一个物理索引
对象就是前边提到的树结构而在你每次运行查询时都访问同一个索引
警告当表被删除时所有与表相关的索引也将被删除
斧子 - 2006-2-11 18:31:00
使用索引的技巧
这里给出了几个在使用索引时需要记住的技巧
l 对于小表来说使用索引对于性能不会有任何提高
l 当你的索引列中有极多的不同的数据和空值时索引会使性能有极大的提高
l 当查询要返回的数据很少时索引可以优化你的查询比较好的情况是少于全部数据的
25% 如果你要返回的数据很多时索引会加大系统开销
l 索引可以提高数据的返回速度但是它使得数据的更新操作变慢在对记录和索引进
行更新时请不要忘记这一点如果要进行大量的更新操作在你执行更新操作时请不
要忘记先删除索引当执行完更新操作后只需要简单的恢复索引即可对于一次特
定的操作系统可以保存删除的索引18 个小时在这个时间内数据更新完后你可以恢
复它
l 索引会占用你的数据库的空间如果你的数据库管理系统允许你管理数据库的磁盘空
间那么在设计数据库的可用空间时要考虑索引所占用的空间
l 对字段的索引已经对两个表进行了归并操作这一技术可以极大地提高归并的速度
l 大多数数据库系统不允许你对视图创建索引如果你的数据库系统允许这样做那么
可以使用这种方法来在SELECT 语句中对视图的数据进行排序很不巧一些数据库
系统中也不允许在视图中使用ORDERY BY 子句
l 不要创建对经常需要更新或修改的字段创建索引更新索引的开销会降低你所期望获
得的性能
l 不要将索引与表存储在同一个驱动器上分开存储会去掉访问的冲突从而使结果返回
得更快
对更多的字段进行索引
SQL 也允许你对多个字段进行索引这种索引被称为复合索引下边的代码是一个简
单的复合索引的例子注意虽然是对两个字段进行索引但索引在物理结构上只有一个
INPUT/OUTPUT
SQL> CREATE INDEX ID_CMPD_INDEX ON BILLS( ACCOUNT_ID, AMOUNT );
Index created.
SQL 21 日自学通(V1.0) 翻译人笨猪
215
SQL> SELECT * FROM BILLS;
NAME AMOUNT ACCOUNT_ID
Florida Water Company 20 1
Power Company 75 1
Phone Company 125 1
Software Company 250 1
Record Club 25 2
Cable TV Company 35 3
Debtor's Credit Card 35 4
U-O-Us Insurance Company 125 5
Joe's Car Palace 350 5
S.C. Student Loan 200 6
SQL> DROP INDEX ID_CMPD_INDEX
Index dropped.
分析
选择唯一值最多的列建立索引可以达到你所希望的性能例如在BILLS 表中NAME
字段中的每一个值都是唯一的当使用复合索引时要把最可能选择的字段放在前边也
就是说把你最经常在查询中使用是字段放在最前边在CREATE INDEX 中列的出现次
序不必与表中的次序一致如果你经常使用下边的语句
SQL> SELECT * FROM BILLS WHERE NAME = "Cable TV Company";
为了想达到所期望的性能你必须在索引中将NAME 字段放在第一位这里有两个例
子
SQL> CREATE INDEX NAME_INDEX ON BILLS NAME, AMOUNT
或
SQL> CREATE INDEX NAME_INDEX ON BILLS NAME
在这两个例子中NAME 都在索引字段的最左边所以这两个索引可以提高对NAME
的查询的性能
复合索引也可以根据他们自己的选择性来对两个以上的字段进行索引作为一个选择
性的例子请看一下下边的这个表
ACCOUNT_ID TYPE BALANCE BANK
1 Checking 500 First Federal
2 Money Market 1200 First Investor's
SQL 21 日自学通(V1.0) 翻译人笨猪
216
ACCOUNT_ID TYPE BALANCE BANK
3 Checking 90 Credit Union
4 Savings 400 First Federal
5 Checking 2500 Second Mutual
6 Business 4500 Fidelity
请注意输出的六个记录checking 值在这里出现了三次所以它的选择性要低于
ACCOUUNT_ID 请注意每一个ACCOUNT_ID 的值都是唯一的要想提高你的索引的
选择性你可以将TYPE 字段与ACCOUNT_ID 字段组合在一起建立一个索引这将将创
建一个唯一的索引值当然这也是你所能得到的最高的选择性
注一个索引可以包含多个列通常是指复合索引复合索引的性能与单个字段的索引相比
是无法断定的以ORACLE 为例如果你在查询条件中经常指定某一特定的列那个你
可以创建这个列的索引而当你的查询需要复合条件时你可以创建复合索引当创建
多个索引的时候你需要参考你所选定的解释器的帮助信息以从中得到确定的复合索引
的用法
在创建索引时使用UNIQUE 关键字
复合索引通常使用UNIQUE 关键字来防止有相同数据的多个记录多次出现例如如
果你想要BILLS 表具有下边的规则每一个账单的交付公司都必须有不同的银行账号你
需要创建一个包括NAME 和ACCOUNT_ID 的唯一索引不幸的是ORACLE7 不支持
UNIQUE 语法它是用UNIQUE 完整性约束来达到内容唯一这一特性的下边的例子中给
出了在Sybase 的Transact-SQL 语言中UNIQUE 关键字的用法
INPUT
1> create unique index unique_id_name
2> on BILLS(ACCOUNT_ID, NAME)
3> go
1> select * from BILLS
2> go
OUTPUT
NAME AMOUNT ACCOUNT_ID
Florida Water Company 20 1
SQL 21 日自学通(V1.0) 翻译人笨猪
217
NAME AMOUNT ACCOUNT_ID
Power Company 75 1
Phone Company 125 1
Software Company 250 1
Record Club 25 2
Cable TV Company 35 3
Debtor's Credit Card 35 4
U-O-Us Insurance Company 125 5
Joe's Car Palace 350 5
S.C. Student Loan 200 6
现在我们试着向表中插入一个已经存在的记录
INPUT
1> insert BILLS (NAME, AMOUNT, ACCOUNT_ID)
2> values("Power Company", 125, 1)
3> go
分析
你会收到了个错误信息告诉你插入操作是不允许的这个错误可以为应用程序所捕获
从而告知用户他插入了一个不合法的数据
例10.3
在BILLS 表中创建一个索引以对AMOUNT 字段进行降序排列
INPUT/OUTPUT
SQL> CREATE INDEX DESC_AMOUNT
ON BILLS(AMOUNT DESC);
Index created.
分析
这是我们第一次使用DESC 操作它将告诉SQL 将索引降序排列通常情况下是升序
排列现在来看一下结果
INPUT/OUTPUT
SQL> SELECT * FROM BILLS;
NAME AMOUNT ACCOUNT_ID
Joe's Car Palace 350 5
Software Company 250 1
SQL 21 日自学通(V1.0) 翻译人笨猪
218
NAME AMOUNT ACCOUNT_ID
S.C. Student Loan 200 6
Phone Company 125 1
U-O-Us Insurance Company 125 5
Power Company 75 1
Cable TV Company 35 3
Debtor's Credit Card 35 4
Record Club 25 2
Florida Water Company 20 1
分析
这个例子对AMOUNT 列使用DESO 操作创建了一个索引注意输出的顺序是从大到
小
斧子 - 2006-2-11 18:31:00
索引与归并
当在查询中使用了复杂的归并时你的SELECT 语句会耗用很长的时间对于大表来
说所用的时间可能会达到好几秒钟与你通常需要等待几毫秒相对比这样的性能在客
户机/服务器环境中常会令你的用户对使用你的应用程序感到不耐烦在归并时对字段创建
索引可以显著地提高你的查询反映速度但是如果你创建太多的索引就会使你的系统
的性能下降而不是提高我们推荐你在几个大表中进行索引试验对数以千计的数据排序
这样的试验可以让你更深入地理解SQL 查询的优化
注大多数的解释器有捕获查询耗用时间的机制ORACLE 将这种特性称为timing 请察
看你所使用的解释器的相关信息
下边的例子对BILS 表与BANK_ACCOUNT 表根据ACCOUNT_ID 字段创建了索引
INPUT/OUTPUT
SQL> CREATE INDEX BILLS_INDEX ON BILLS(ACCOUNT_ID);
Index created.
SQL> CREATE INDEX BILLS_INDEX2 ON BANK_ACCOUNTS(ACCOUNT_ID);
Index created.
SQL> SELECT BILLS.NAME NAME, BILLS.AMOUNT AMOUNT,
BANK_ACCOUNTS.BALANCE ACCOUNT_BALANCE
FROM BILLS, BANK_ACCOUNTS
SQL 21 日自学通(V1.0) 翻译人笨猪
219
WHERE BILLS.ACCOUNT_ID = BANK_ACCOUNTS.ACCOUNT_ID
NAME AMOUNT ACCOUNT_BALANCE
Phone Company 125 500
Power Company 75 500
Software Company 250 500
Florida Water Company 20 500
Record Club 25 1200
Cable TV Company 35 90
Debtor's Credit Card 35 400
Joe's Car Palace 350 2500
U-O-Us Insurance Company 125 2500
S.C. Student Loan 200 4500
分析
这个例子中首次在相关的表中为ACCOUNT_ID 字段创建了索引在每一个表中均对
ACCOUNT_ID 字段创建了索引以后归并就可以更快地访问特定行的数据作为一个规
则你应该对表中的唯一属性的字段或你用以归并操作的字段来创建索引
群集簇的使用
尽管在开始的时候我们曾经说过索引只是提供给用户的一种与数据的物理存在不同的
查看方式但是这话并不是绝对的在许多数据管理系统中都支持一种特殊的可以允许
数据库管理员或开发人员对数据进行群集的索引当使用群集索引时数据在表中的物理
排列方式将会被修改使用群集索引通常比传统的不使用群集的索引速度要快但是许
多数据库管理系统如Sybase 的SQL Server 只允许一个表有一个群集索引用于创建群
集索引的字段常常是主关键字用Sybase 的Transact-SQL 你可以对BANK_ACCOUNT 的
ACCOUNT_ID 字段创建一个群集的不重复的索引语法如下
SYNTAX
create unique clustered index id_index on BANK_ACCOUNTS(ACCOUNT_ID)
go
ORACLE 中群集的概念与此不同当使用ORACLE 关系数据库系统时群集就是一
个像数据或表一样的对象群集一般是存储了表的共有字段以提高对表的访问速度
这是一个ORACLE7 中创建群集的例子
SQL 21 日自学通(V1.0) 翻译人笨猪
220
SYNTAX
CREATE CLUSTER [schema.]cluster (column datatype [,column datatype] ... )
[PCTUSED integer] [PCTFREE integer] [SIZE integer [K|M] ]
[INITRANS integer] [MAXTRANS integer] [TABLESPACE tablespace]
[STORAGE storage_clause] [!!under!!INDEX | [HASH IS column] HASHKEYS integer]
你随后创建的其于该表的群集的索引会被加入到群集中然后把表也加入群集中你
应该只将经常需要归并的表加入到群集不要向群集中加入只需要用简单的SELECT 语句
进行个别访问的表
很明显群集是SQL 的第三方特性所以我们不准备详细地讨论创建和使用它的语法
的细节问题但是你要查看你的数据库系统的文档看它是否支持这一有用的特性
总结
视图是一种虚表视图是提供给用户的数据与其在数据库的真实面貌不相同的一种方
法CREATE VIEW 语法的语法使用了标准的SELECT 语法来创建了一个视图除了一些
小差别你可以将视图视为一个常规的表来执行插入删除更新和选择操作我们也简
要地提到了视图是实现数据库安全的一种重要方法有关数据的安全性将在第12 天作更详
细的讨论
基本的创建视图的语法如下
CREATE VIEW view_name AS SELECT field_name(s) FROM table_name(s)
视图主要用于以下方面
l 提高用户数据的安全性
l 进行单位换算
l 创建一个新格式的虚表
l 使复杂查询的构筑简单化
索引也是一种数据库设计和SQL 编程的工具索引是一种存储在你的数据库管理系统
中的物理对象它可以让你的查询更快地从数据库中返回数据此外索引是可以定制的
正确地在查询中使用索引可以使性能显著地提高
创建索引的基本语法如下
CREATE INDEX index_name ON table_name field_name s
SQL 21 日自学通(V1.0) 翻译人笨猪
221
在一些数据库系统中提供了一些非常有用的如UNIQUE 和CLUSTER 关键字附加选
项
问与答
问如果数据已经在我的数据库中进行了排序我是否还有必须在表中使用索引
答索引通过在树结构中查找关键值而提高你的数据库查询性能它比对数据库的顺序访
问方式快得多记住SQL 不需要知道你的数据库是否已经进行了排序
问我可以创建一个包括多个表中字段的索引吗
答你不能但是以ORACLE 为例它允许你创建一个群集你可以将表放入群集中以
根据表的共有字段创建一个群集索引这是它的一个例外所有你应该查看你所使用
的解释器的文档以找到这方法的详细解答
校练场
1 当在一个不唯一的字段中创建一个唯一值索引会有什么结果
2 下边的话是对是错
视图和索引都会占用数据库的空间所以在设计数据库空间时要考虑到这一点
如果一个从更新了一个已经创建视图的表那么视图必须进行同样的更新才会看到相同
的数据
如果你的磁盘空间够而你想加快你的查询的速度那么索引越多越好
3 下边的CREATE 语句是否正确
SQL> create view credit_debts as (select all from debts where account_id = 4)
4 下边的CREATE 语句是否正确
SQL> create unique view debts as select * from debts_tbl
5 下边的CREATE 语句是否正确
SQL> drop * from view debts
6 下边的CREATE 语句是否正确
SQL> create index id_index on bills account_id
SQL 21 日自学通(V1.0) 翻译人笨猪
222
练习
1 检查你所使用的数据库系统它是否支持视图允许你在创建视图时使用哪些选项用
它的语法来写一个简单的创建视图语句并对其进行如SELECT 和DELETE 等常规操
作后再删除视图
2 检查你所使用的数据库系统看它是否支持索引它有哪些选项在你的数据库系统中的
一些已经存在的表中试一下这些选项进一步确认在你的数据库系统中是否支持
UNIQUE 和CLUSTER 索引
3 如果可能的话在一个表中输入几千条记录用秒表或钟来测定一下你的数据库系统对
特定操作的反映时间加入索引是否使性能提升了试一下今天提到的技巧
斧子 - 2006-2-11 18:32:00
第11 天事务处理控制
前十天中我们学习了实际上我们可以对关系数据库系统中的数据所做的每一件事例
如我们已经知道了如何使用SQL 的SELECT 语句根据用户给定的条件从一个或多个表
中获得数据我们也有机会体验了数据修改语句如INSERT DELETE UPDATE 在今天
我们将成为中级SQL 用户如果有必要我们将建立一个数据库及其相关的表每一个表
中都包括几个不同类型的字段通过合适的设计方法我们会成为从数据库到应用程序的
桥梁
目标
如果你是一个临时用户只需要偶而使用SQL 从数据库获得数据的话那么前十天的
的主题已经为你提供了足够的内容但是如果你想开发可以在使用数据库系统下运行的
专业应用程序这在当前在很普遍的那么你在今后四天中讲到的内容事务控制安全
内嵌SQL 语句数据库过程将会对你有很大的帮助我们先从事务控制开始到今天的
结束我们将学会以下内容
l 基本的事务控制
l 如何确认或终止某一项事务
l Sybase 与Oracle 在事务处理上的不同之处
注在今天的例子中我们使用PERSONAL ORACLE 7和SYBASE SQL SERVER 对于你
所使用的解释器请查看相应的帮助文档以找出它们的不同之处
事务控制
事务控制或者说事务处理是指关系数据库系统执行数据库事务的能力事务是指在逻
辑上必须完成的一命令序列的单位单元工作期是指事务的开始和结束时期如果在事务
中产生的错误那么整个过程可以根据需要被终止如果每一件事都是正确的那么结果
将会被保存到数据库中
日后你也许会运行其于网络的多用户应用程序客户/服务环境就是为它而设计的传
SQL 21 日自学通(V1.0) 翻译人笨猪
224
统上的服务器例如数据库服务器支持多个与它连接的工作站与其它技术一样新特
性提高了数据库的复杂程度下边的几段描述了一个银行所使用的应用程序
银行应用程序
假定你受雇于联邦银行并负责为他们设计一个支票管理系统你已经设计了一个非常
完美的数据库并且经常测试检验证明是正确无误的你在应用程序中调用它以后你从
账号中支取了20 元并进行验证数据库中确实已经少了20 元你又从帐号中存入了50.25
元并进行验证结果也与所期望的相同于是你骄傲在告诉你的老板系统可以运行了几
台计算机接入了程序并开始工作
几分钟以后你注意到了一个你没有预见的问题一个出纳员向帐号中存入了一张支
票而另一个出纳则从相同的帐号中提出了一部分钱在分钟之内由于多用户的同时操作
就导致的帐目无法平衡很不幸由于他们之间互相进行更新和写入操作你的应用程序
很快就因为过负荷而断线我们假定出现这个问题的数据库名字叫CHECKING 它有两个
表其内容如下所示
表11.1
Name Address City State Zip Customer_ID
Bill Turner 725 N. Deal Parkway Washington DC 20085 1
John Keith 1220 Via De Luna Dr. Jacksonville FL 33581 2
Mary Rosenberg 482 Wannamaker Avenue Williamsburg VA 23478 3
David Blanken 405 N. Davis Highway Greenville SC 29652 4
Rebecca Little 7753 Woods Lane Houston TX 38764 5
表11.2
Average_Bal Curr_Bal Account_ID
1298.53 854.22 1
5427.22 6015.96 2
211.25 190.01 3
73.79 25.87 4
1285.90 1473.75 5
1234.56 1543.67 6
345.25 348.03 7
假定你的应用程序为BILL Turner 运行了SELECT 查询并得到如下结果
OUTPUT
SQL 21 日自学通(V1.0) 翻译人笨猪
225
NAME Bill Turner
ADDRESS 725 N. Deal Parkway
CITY Washington
STATE DC
ZIP 20085
CUSTOMER_ID 1
当返回数据的时候另外一个用户连接到了数据库并更新了BILL Turner 的住址信息
INPUT
SQL> UPDATE CUSTOMERS SET Address ="11741 Kingstowne Road"
WHERE Name = "Bill Turner"
你现在看到了如果在你执行SELECT 语句当中出现的更新操作的话那么你所得到的
结果将是不正确的如果你的应用程序可以生成一个信件给Bill Turner 那么由于地址是
错误的如果信已经发送了那你是不能对地址进行修改的但是如果你使用了事务处理
机制那么你就可以对检测到错误的数据进行修改你所进行的所有操作也都可以撤消
开始事务处理
事务处理在执行上是非常简单的你需要检查你所执行的语法是Oracle RDBMS SQL
语法还是Sybase SQL Server SQL 语法
所有支持事务处理的系统都必须以一种准确的语法来告诉系统一项事务是如何开始的
不要忘记事务处理只是工作的逻辑分组它有自己的开始和结束在使用PERSONAL
ORACLE7 时它的语法形式如下
SYNTAX
SET TRANSACTION {READ ONLY | USE ROLLBACK SEGMENT segment}
SQL 标准要求每一种数据库的SQL 解释器都必须运支持语句级的读一致这也就是
说当某一条语句运行的时候数据必需保持不变但是在许多情况下在一个工作过程中
必须要求数据保持有效而不仅仅是对单个语句ORACLE 允许用户用SET TRANSACTION
来指定事务的开始如果你想检查BILL TUNER 的信息并且要保证数据在这之中是不能改
变的那么你可以使用如下语句
INPUT
SQL 21 日自学通(V1.0) 翻译人笨猪
226
SQL> SET TRANSACTION READ ONLY
SQL> SELECT * FROM CUSTOMERS
WHERE NAME = 'Bill Turner';
SQL> COMMIT
我们将在今天的晚些时候来讨论COMMIT 语句这里的SET TRANSACTION READ
ONLY 允许你锁定一个记录集直到事务结束你可以在下列语句中使用READ ONLY 选项
SELECT
LOCK TABLE
SET ROLE
ALTER SESSION
ALTER SYSTEM
选项USE ROLLBACK SEGMENT 告诉ORACLE 数据库提供数据回溯的存储空间段
这一选项是ORACLE 对标准的SQL 的扩展如果需要维护你的数据库请参见ORACLE 的
帮助文档以获得更多的帮助信息
SQL Server's Transact-SQL 语言用下边的方法来实现了开始事务处理的命令
SYNTAX
begin {transaction | tran} [transaction_name]
它的实现方法与ORACLE 的有一些不同SYBASE 不允许你指定READ ONLY 选
项但是SYBASE 允许你给出事务处理的名字从最早的事务到最近发生的事务处理都
可以一次退回
INPUT
1> begin transaction new_account
2> insert CUSTOMERS values ("Izetta Parsons", "1285 Pineapple Highway", "Greenville", "AL"
32854, 6)
3> if exists(select * from CUSTOMERS where Name = "Izetta Parsons")
4> begin
5> begin transaction
6> insert BALANCES values(1250.76, 1431.26, 8)
7> end
8> else
SQL 21 日自学通(V1.0) 翻译人笨猪
227
9> rollback transaction
10> if exists(select * from BALANCES where Account_ID = 8)
11> begin
12> begin transaction
13> insert ACCOUNTS values(8, 6)
14> end
15> else
16> rollback transaction
17> if exists (select * from ACCOUNTS where Account_ID = 8 and Customer_ID = 6)
18> commit transaction
19> else
20> rollback transaction
21> go
现在请不要担心ROLLBACK TRANSACTION 和COMMIT TRANSACTION 语句
重要的问题是这是一个内嵌的事务处理或者说是事务处理之中还有事务处理
注意最开始的事务处理在第1 行之后是插入语句你检查了插入确实已经执行了
以后第二个事务处理在第5 行开始这种在事务之中的事务在术语上称为内嵌事务
有一些数据库支持AUTOCOMMIT 选项它可以在SET 命令中使用如下例
SET AUTOCOMMIT [ON | OFF]
默认情况上SET AUTOCOMMIT ON 命令在启动时是自动运行的它告诉SQL 自动确
认你所运行的所有的语句如果你不想让这个命令自动运行那么请将它的参数设为NO
SET AUTOCOMMIT OFF
注请检查你的数据库文档确认在你的数据库系统中一项事务处理是如何开始的
斧子 - 2006-2-11 18:33:00
结束事务处理
在ORACLE 语法中结束事务处理语句的语法如下
SYNTAX
COMMIT [WORK]
[ COMMENT 'text'
SQL 21 日自学通(V1.0) 翻译人笨猪
228
| FORCE 'text' [, integer] ] ;
它的命令语法与Sybase 的语法是相同的
语法
COMMIT (TRANSACTION | TRAN | WORK) (TRANSACTION_NAME)
COMMIT 命令将保存在一项事务中所进行的所有的改变在开始一项事务处理之前要
先运行COMMIT 命令以确保在之前没有事务未被确认
在下边的例子中如果COMMIT 没有收到任何系统错误的情况下它将会执行确认
INPUT
SQL> COMMIT;
SQL> SET TRANSACTION READ ONLY;
SQL> SELECT * FROM CUSTOMERS
WHERE NAME = 'Bill Turner';
---Do Other Operations---
SQL> COMMIT;
在ORACLE 中COMMIT 语句的使用方法如下
INPUT
SQL> SET TRANSACTION;
SQL> INSERT INTO CUSTOMERS VALUES
("John MacDowell", "2000 Lake Lunge Road", "Chicago", "IL", 42854, 7);
SQL> COMMIT;
SQL> SELECT * FROM CUSTOMERS;
CUSTOMER 表的内容如下
Name Address City State Zip Customer_ID
Bill Turner 725 N. Deal Parkway Washington DC 20085 1
John Keith 1220 Via De Luna Dr. Jacksonville FL 33581 2
Mary Rosenberg 482 Wannamaker Avenue Williamsburg VA 23478 3
David Blanken 405 N. Davis Highway Greenville SC 29652 4
Rebecca Little 7753 Woods Lane Houston TX 38764 5
Izetta Parsons 1285 Pineapple Highway Greenville AL 32854 6
John MacDowell 2000 Lake Lunge Road Chicago IL 42854 7
而Sybase SQL 使用COMMIT 的语法方式如下
SQL 21 日自学通(V1.0) 翻译人笨猪
229
INPUT
1>begin transaction
2>insert into CUSTOMERS values
("John MacDowell", "2000 Lake Lunge Road", "Chicago", "IL", 42854, 7)
3>commit transaction
4>go
1>select * from CUSTOMERS
2>go
Name Address City State Zip Customer_ID
Bill Turner 725 N. Deal Parkway Washington DC 20085 1
John Keith 1220 Via De Luna Dr. Jacksonville FL 33581 2
Mary Rosenberg 482 Wannamaker Avenue Williamsburg VA 23478 3
David Blanken 405 N. Davis Highway Greenville SC 29652 4
Rebecca Little 7753 Woods Lane Houston TX 38764 5
Izetta Parsons 1285 Pineapple Highway Greenville AL 32854 6
John MacDowell 2000 Lake Lunge Road Chicago IL 42854 7
上边的语句完成了与ORACLE7 相同的功能但是在使用COMMIT 确认事务处理
之前你应该确保在该事务中的工作是正确无误的
注COMMIT WORD 命令与COMMIT 命令的作用是相同的或Sybase 中的COMMIT
TRANSACTION 它与ANSI SQL 的语法一样的简单
切记COMMIT 语句一定要与之前的SET TRANSCATION 或BEGIN TRANSCATION
语句一致注意在下边的语句中你将会收到错误信息
Oracle SQL
INPUT
SQL> INSERT INTO BALANCES values (18765.42, 19073.06, 8);
SQL> COMMIT WORK;
Sybase SQL
INPUT
1> insert into BALANCES values (18765.42, 19073.06, 8)
2> commit work
SQL 21 日自学通(V1.0) 翻译人笨猪
230
取消事务处理
在一个事务处理的过程中常常会运行一些错误检查以确认在过程中是否语句是运行
成功你可以使用ROLLBACK 语句来撤消事务中所做的每一项工作即便工作是成功的
你也可以撤消但是这必须是在COMMIT 之前ROLLBACK 语句必须在一个事务之中
运行它可以一直撤消到事务的开始也就是说数据库会一直返回到事务处理刚开始的
状态在ORACLE 7 中它的语法形式如下
SYNTAX
ROLLBACK [WORK]
[ TO [SAVEPOINT] savepoint
| FORCE 'text' ]
如你所见该命令可以设置事务的SAVEPOINT 我们将在今天的晚些时候来讨论这
项技术
Sybase Transact-SQL's 的ROLLBACK语句与COMMIT 语句非常相似
SYNTAX
rollback {transaction | tran | work} [transaction_name | savepoint_name]
一个ORACLE 的命令序列如下
INPUT
SQL> SET TRANSACTION;
SQL> INSERT INTO CUSTOMERS VALUES
("Bubba MacDowell", "2222 Blue Lake Way", "Austin", "TX", 39874, 8);
SQL> ROLLBACK;
SQL> SELECT * FROM CUSTOMERS;
Name Address City State Zip Customer_ID
Bill Turner 725 N. Deal Parkway Washington DC 20085 1
John Keith 1220 Via De Luna Dr. Jacksonville FL 33581 2
Mary Rosenberg 482 Wannamaker Avenue Williamsburg VA 23478 3
David Blanken 405 N. Davis Highway Greenville SC 29652 4
Rebecca Little 7753 Woods Lane Houston TX 38764 5
Izetta Parsons 1285 Pineapple Highway Greenville AL 32854 6
John MacDowell 2000 Lake Lunge Road Chicago IL 42854 7
SQL 21 日自学通(V1.0) 翻译人笨猪
231
而A Sybase SQL 的命令序列则如下
INPUT
1> begin transaction
2> insert into CUSTOMERS values
("Bubba MacDowell", "2222 Blue Lake Way", "Austin", "TX", 39874, 8)
3> rollback transaction
4> go
1> SELECT * FROM CUSTOMERS
2> go
Name Address City State Zip Customer_ID
Bill Turner 725 N. Deal Parkway Washington DC 20085 1
John Keith 1220 Via De Luna Dr. Jacksonville FL 33581 2
Mary Rosenberg 482 Wannamaker Avenue Williamsburg VA 23478 3
David Blanken 405 N. Davis Highway Greenville SC 29652 4
Rebecca Little 7753 Woods Lane Houston TX 38764 5
Izetta Parsons 1285 Pineapple Highway Greenville AL 32854 6
John MacDowell 2000 Lake Lunge Road Chicago IL 42854 7
你也看到了由于使用了ROLLBACK 命令撤消了INSERT 命令新的记录并没有被
加入到表中
如果你写了一个图形用户界面的应用程序比如MICRO WINDOWS 你可以做一个
数据库查询对话框以便让用户在其中输入数值如果用户按下了确定按钮那么数据
库将会保存所做的改动如果用户按下了取消按钮那么所有的更改就会被取消显
然这种情况给予了你使用事务处理的机会
注下边的代码给出的ORACLE SQL 中的使用方法注意这里有SQL>并且有行号
在随后给出的Sybase SQL syntax 中则没有SQL>提示符
当对话框载入后这些SQL 语句将会运行
INPUT
SQL> SET TRANSACTION;
SQL> SELECT CUSTOMERS.NAME, BALANCES.CURR_BAL, BALANCES.ACCOUNT_ID
2 FROM CUSTOMERS, BALANCES
3 WHERE CUSTOMERS.NAME = "Rebecca Little"
SQL 21 日自学通(V1.0) 翻译人笨猪
232
4 AND CUSTOMERS.CUSTOMER_ID = BALANCES.ACCOUNT_ID;
该对话框允许用户更改当前的结算账号所以你需要将该数据返回给数据库
当按下OK 按钮以后UPDATE将会运行
INPUT
SQL> UPDATE BALANCES SET CURR_BAL = 'new-value' WHERE ACCOUNT_ID = 6;
SQL> COMMIT
如果用户按下了CANCEL 那么将会运行ROLLBACK命令
INPUT
SQL> ROLLBACK
当该对话框在Sybase SQL 中被载入以后将会运行下边的语句
INPUT
1> begin transaction
2> select CUSTOMERS.Name, BALANCES.Curr_Bal, BALANCES.Account_ID
3> from CUSTOMERS, BALANCES
4> where CUSTOMERS.Name = "Rebecca Little"
5> and CUSTOMERS.Customer_ID = BALANCES.Account_ID
6> go
该对话框允许用户改变当前的结算账号当你将该数据返回给数据库以后并按下OK
按钮时UPDATE语句将会运行
INPUT
1> update BALANCES set Curr_BAL = 'new-value' WHERE Account_ID = 6
2> commit transaction
3> go
如果用户选择了CANCEL 按钮那么将会执行ROLLBACK的语句
INPUT
1> rollback transaction
2> go
ROLLBACK 语句将会终止整个事务当存在嵌套事务时ROLLBACK 将会终止掉全
部事务系统将会返回到事务开始的最初状态
如果当前没有活动的事务时ROLLBACK 或COMMIT 语句将不会对数据库产生任何作用你可以认为这是一个无效的命令
在COMMIT 语句运行以后在事务中的所有动作都会得到确认这时在使用
ROLLBACK命令就太晚了
斧子 - 2006-2-11 18:33:00
在事务中使用保存点
在事务中使用ROLLBACK 可以取消整个的事务但是你也可以在你的事务当中使用
语句进行部分地确认在Sybase 和Oracle 中都允许你在当前事务中设一个保存点从
这一点开始如果你使用了ROLLBACK 命令那么系统将会回到保存点时的状态而在
保存点之前的语句将会得到确认在ORACLE 中创建一个保存点的语法格式如下
SYNTAX
SAVEPOINT savepoint_name;
在SYBASE 中创建保存点的语法格式如下
SYNTAX
save transaction savepoint_name
下边是使用ORACLE 语法的例子
INPUT
SQL> SET TRANSACTION
SQL> UPDATE BALANCES SET CURR_BAL = 25000 WHERE ACCOUNT_ID = 5
SQL> SAVEPOINT save_it
SQL> DELETE FROM BALANCES WHERE ACCOUNT_ID = 5
SQL> ROLLBACK TO SAVEPOINT save_it
SQL> COMMIT
SQL> SELECT * FROM BALANCES
结算平衡表的内容如下
Average_Bal Curr_Bal Account_ID
1298.53 854.22 1
5427.22 6015.96 2
211.25 190.01 3
73.79 25.87 4
1285.90 25000.00 5
SQL 21 日自学通(V1.0) 翻译人笨猪
234
1234.56 1543.67 6
345.25 348.03 7
1250.76 1431.26 8
下边是使用Sybase 语法的例子
INPUT:
1> begin transaction
2> update BALANCES set Curr_Bal = 25000 where Account_ID = 5
3> save transaction save_it
4> delete from BALANCES where Account_ID = 5
5> rollback transaction save_it
6> commit transaction
7> go
1> select * from BALANCES
2> go
Average_Bal Curr_Bal Account_ID
1298.53 854.22 1
5427.22 6015.96 2
211.25 190.01 3
73.79 25.87 4
1285.90 25000.00 5
1234.56 1543.67 6
345.25 348.03 7
1250.76 1431.26 8
在上边的例子中创建了一个叫SAVE_IT 的保存点UPDATE 语句更新了结算平衡表中
的CURR_BAL 列你在其后设置了一个保存点在保存之后你又运行了DELETE 命令
系统退回到了保存点处之后你对事务用COMMIT 命令进行了确认结果所有在保存点
之前的命令得到了确认
如果你在其后又使用了ROLLBACK 命令那么将会取消当前的事务而不会有任何的
改变
在ORACLE 中的例子如下
INPUT
SQL> SET TRANSACTION
SQL 21 日自学通(V1.0) 翻译人笨猪
235
SQL> UPDATE BALANCES SET CURR_BAL = 25000 WHERE ACCOUNT_ID = 5
SQL> SAVEPOINT save_it
SQL> DELETE FROM BALANCES WHERE ACCOUNT_ID = 5
SQL> ROLLBACK TO SAVEPOINT save_it
SQL> ROLLBACK
SQL> SELECT * FROM BALANCES
BALANCE 表的内容如下
Average_Bal Curr_Bal Account_ID
1298.53 854.22 1
5427.22 6015.96 2
211.25 190.01 3
73.79 25.87 4
1285.90 1473.75 5
1234.56 1543.67 6
345.25 348.03 7
1250.76 1431.26 8
Sybase SQL 语法的例子如下
INPUT
1>begin transaction
2>update BALANCES set Curr_Bal = 25000 where Account_ID = 5
3>save transaction save_it
4>delete from BALANCES where Account_ID = 5
5>rollback transaction save_it
6>rollback transaction
7>go
1>select * from BALANCES
2>go
Average_Bal Curr_Bal Account_ID
1298.53 854.22 1
5427.22 6015.96 2
211.25 190.01 3
73.79 25.87 4
SQL 21 日自学通(V1.0) 翻译人笨猪
236
1285.90 1473.75 5
1234.56 1543.67 6
345.25 348.03 7
1250.76 1431.26 8
总结
事务可以被定义为一个有组织的工作单元事务通常会执行一系列的以前学过的操作
如果由于一些原因使得操作没有如所期望地执行那么可以在事务中取消这些操作反之
如果操作全部正确执行了那么事务中的工作可以确认
可以使用ROLLBACK 命令来取消事务确认事务的命令为COMMIT SQL 用非常相
似的语法来支持这两类过程
SYNTAX
BEGIN TRANSACTION
statement 1
statement 2
statement 3
ROLLBACK TRANSACTION
或
SYNTAX
BEGIN TRANSACTION
statement 1
statement 2
statement 3
COMMIT TRANSACTION
问与答
问如果我有一组事务其中一个是不成功的我是否可以确认其它的事务过程
答不可以必须整组的事务都是成功的才可以
问在使用的COMMIT 命令以后我发现我犯了一个错误那么我怎样才能更正这个错
SQL 21 日自学通(V1.0) 翻译人笨猪
237
误
答使用DELETE INSERT 或UPDATE 语句ROLLBACK在这时是不行的
问在怎个事务结束以后我都必须使用COMMIT 命令确认吗
答不必但是在确认没有错误而且在之前没有事务在运行时使用COMMIT 会更安全
斧子 - 2006-2-11 18:34:00
校练场
1 在嵌套的事务中是否可以使用ROLLBACK 命令来取消当前事务并回退到上级事务
中为什么
2 使用保存点是否可以保存事务的一部分为什么
3 COMMIT 命令是否可以单独使用它一定要嵌套吗
4 如果你在COMMIT 命令后发现的错误你是否还可以使用ROLLBACK命令
4 在事务中使用保存点是否可以自动地将之前的改动自动地保存
练习
1 使用PERSONAL ORACLE7 的语法来更正下边的语法
SQL> START TRANSACTION INSERT INTO CUSTOMERS VALUES ('SMITH', 'JOHN')
SQL> COMMIT
2 使用PERSONAL ORACLE7 的语法来更正下边的语法
SQL> SET TRANSACTION
UPDATE BALANCES SET CURR_BAL = 25000
SQL> COMMIT
3 使用PERSONAL ORACLE7 的语法来更正下边的语法
SQL> SET TRANSACTION
INSERT INTO BALANCES VALUES ('567.34', '230.00', '8')
SQL> ROLLBACK
© 2000 - 2026 Rising Corp. Ltd.