文章教程

中级通信工程师考试13.1.3关系数据库标准语言SQL

8/24/2020 11:08:17 PM 人评论 次浏览

13.1.3 关系数据库标准语言SQL

SQL是一种介于关系代数与关系演算之间的结构化査询语言,其功能不仅是査询。SQL是一个通用的、功能极强的关系数据库语言。

1.SQL概述

SQL之所以能够为用户和业界所接受,并成为国际标准,是因为它是一个综合的、功能极强同时又简捷易学的语言。SQL集数据查询(Data Query)、数据操纵(Data Manipulation)、数据定义(Data Definition)和数据控制(Data Control)功能于一体。

(1)SQL的主要特点

1)综合统一

数据库系统的主要功能是通过数据库支持的数据语言来实现的。

SQL集数据定义语言DDL、数据操纵语言DML、数据控制语言DCL的功能于一体,语言风格统一,可以独立完成数据库生命周期中的全部活动,包括定义关系模式、插入数据、建立数据库、査询、更新、维护、数据库重构、数据库安全性控制等一系列操作要求,这就为数据库应用系统的开发提供了良好的环境。用户在数据库系统投入运行后,还可根据需要随时地逐步地修改模式,且并不影响数据库的运行,从而使系统具有良好的可扩展性。

2)高度非过程化

非关系数据模型的数据操纵语言是面向过程的语言,用其完成某项请求,必须指定存取路径。而用SQL进行数据操作,只要提出“做什么”,而无需指明“怎么做”,因此无需了解存取路径,存取路径的选择以及SQL语句的操作过程由系统自动完成。这不但大大减轻了用户负担,而且有利于提高数据独立性。

3)面向集合的操作方式

非关系数据模型采用的是面向记录的操作方式,操作对象是一条记录。而SQL采用集合操作方式,不仅操作对象、查找结果可以是元组的集合,而且一次插入、删除、更新操作的对象也可以是元组的集合。

4)以同一种语法结构提供两种使用方式

SQL既是自含式语言,又是嵌入式语言。作为自含式语言,它能够独立地用于联机交互的使用方式,用户可以在终端键盘上直接键入SQL命令对数据库进行操作;作为嵌入式语言,SQL语句能够嵌入到高级语言程序中,供程序员设计程序时使用。而在两种不同的使用方式下,SQL语句的语法结构基本上是一致的。这种以统一的语法结构提供两种不同的使用方式的做法,提供了极大的灵活性与方便性。

5)语言简捷,易学易用

SQL功能极强,但由于设计巧妙,语言十分简捷,完成核心功能只用了9个动词,如表13-1所示。SQL接近英语,因此容易学习,容易使用。

表13-1 SQL语言的动词

6)支持三级模式结构

三级模式结构是一种使数据库管理系统能对数据库中数据进行有效组织和管理的技术,标准SQL支持这种三级模式结构。

(2)SQL语言的基本概念

·基本表。基本表也称为关系或表,是数据库中独立存在的表,由CREA TETABLE命令创建。为了提高对基本表的査询速度,可以对一个基本表建立若干索引,这些索引都依附于该基本表且存放在数据库文件中。

·属性和属性名。基本表中的每一列称为一个属性,它规定每列数据的性质:每列第一行的字符串称为列名或属性名,有时也简称属性。

·表结构和元组。基本表属性名的集合称为表结构。基本表中除表结构以外的每一行称为一个元组或数据行。一个基本表由表结构和许多元组构成。

·属性值。基本表中每个元组的一个数据称为一个属性值。

·视图。视图是从一个或几个基本表导出的表,由CREA TEVIEW命令创建。视图不独立存储在数据库中,即数据库中只存放视图的定义而不存放视图对应的数据,这些数据仍存放在导出视图的基本表中,因此视图是一个虚表。视图在概念上与基本表等同,用户可以在视图上再定义视图。

·存储文件。存储文件也称为数据库文件,它由若干个基本表组成。存储文件的物理结构是任意的,对用户是透明的。

2.数据定义

关系数据库系统支持三级模式结构,其模式、外模式和内模式中的基本对象有表、视图和索引。因此SQL的数据定义功能包括定义表、定义视图和定义索引,如表13-2所示。

表13-2 SQL的数据定义语句

视图是基于基本表的虚表,索引是依附于基本表的,因此SQL通常不提供修改视图定义和修改索引定义的操作。用户如果想修改视图定义或索引定义,只能先将它们删除掉,然后再重建。下面就一些比较重要的语句进行解析。

(1)创建基本表

建立数据库最重要的一步就是定义一些基本表。SQL使用CREATETABLE语句定义基本表,其一般格式如下。

CREATE TABLE<表名>(<列名><数据类型>[列级完整性约束条件],

[<列名><数据类型>[列级完整性约束条件]]…

[,<表级完整性约束条件>]);

其中,<表名>是所要定义的基本表的名字,它可以由一个或多个属性<列>组成。

建表的同时通常还可以定义与该表有关的完整性约束条件,这些完整性约束条件被存入系统的数据字典中,当用户操作表中数据时由DBMS自动检查该操作是否违背这些完整性约束条件。如果完整性约束条件涉及该表的多个属性列,则必须定义在表级上,否则既可以定义在列级,也可以定义在表级。

例如如下示例,创建了一个dbo.CategoriesNew表,同时描述了表中的列,每列的数据类型和每列是否允许为Null值。


CREATE TABLE dbo.CategoriesNew
(CategoryID intIDETITY (1,1) NOT NULL
,
CategoryName nvarchar(15) NOT NULL
,
Description ntext NULL
,
Picture image NULL)

(2)修改基本表

1)一般格式

随着应用环境和应用需求的变化,有时需要修改己建立好的基本表,SQL用ALTER TABLE语句修改基本表,其一般格式如下。

ALTER TABLE<表名>

[ADD<新列名><数据类型>[完整性约束]]

[DROP<完整性约束名>]

[MODIFY<列名><数据类型>]

其中,<表名>是要修改的基本表,ADD子句用于增加新列和新的完整性约束条件,DROP子句用于删除指定的完整性约束条件,MODIFY子句用于修改原有的列定义,包括修改列名和数据类型。

2)示例

·增加字段。

ALTER TABLE products ADD COLUMN description text;

·删除字段。

ALTER TABLE products DROP COLUMN description;

·增加约束。

ALTER TABLE products ADD CONSTRAINT some_name UNIQUE (product_no);

·删除约束。

ALTER TABLE products DROP CONSTRAINT some_name;

·改变一个字段的默认值。

ALTER TABLE products MODIFY COLUMN price SET DEFAULT 7.77;

·修改一个字段的数据类型。

ALTER TABLE products MODIFY COLUMN price TYPE numeric (10, 2);

·给一个字段重命名。

ALTER TABLE products RENAME COLUMN product_no TO product_number;

(3)删除基本表

1)说明

删除表使用DROP TABLE命令。删除表将删除该表的所有行和行内的数据,如果数据包含大对象类型和嵌套表,以及对表的分区、索引、触发器等都将无条件地被删除。该语句将释放所有原表占用的资源。

2)示例


DROP TABL E employees;

该语句删除表employees。

(4)建立索引

1)说明

建立索引是加快査询速度的有效手段。用户可以根据应用环境的需要,在基本表上建立—个或多个索引,以提供多种存取路径,加快查找速度。

在SQL中,建立索引使用CREATE INDEX语句,其一般格式如下。

CREATE [UNIQUE] INDEX<索引名>

ON<表名>(<列名>[<次序>][,<列名>[<次序>]...);

其中,<表名>是要建索引的基本表的名字。索引可以建立在该表的一列或多列上,各列名之间用逗号分隔。每个<列名>后面还可以用<次序>指定索引值的排列次序,可选ASC(升序)或DESC(降序),默认值为ASC。

UNIQUE表明此索引的每一个索引值只对应唯一的数据记录。

2)示例


CREATE INDEX prod_idx ON product_information_part(product_id)

该语句为表product_information_part的product_id字段创建了prod_idx索引。

(5)删除索引

索引一经建立,就由系统使用和维护它,不需用户干预。建立索引是为了减少査询操作的时间,但如果数据增加删改频繁,系统会花费许多时间来维护索引。这时,可以删除一些不必要的索引。

在SQL中,删除索引使用DROP INDEX语句,其一般格式如下。

DROP INDEX<索引名>;

删除索引时,系统会同时从数据字典中删去有关该索引的描述。

(6)定义视图

1)视图

视图是关系数据库系统提供给用户以多种角度观察数据库中数据的重要机制。

视图是从一个或几个基本表(或视图)导出的表,它与基本表不同,是一个虚表。数据库中只存放视图的定义,而不存放视图对应的数据,这些数据仍存放在原来的基本表中。因此,基本表中的数据发生变化,从视图中查询出的数据也就随之改变了。从这个意义上讲,视图就像一个窗口,透过它可以看到数据库中自己感兴趣的数据及其变化。

视图一经定义,就可以和基本表一样被查询、被删除,也可以在一个视图之上再定义新的视图,但对视图的更新(如增加、删除、修改)操作则有一定的限制。

SQL用CREATE VIEW命令建立视图,其一般格式如下。

CREATE VIEW<视图名>[(<列名>[,<列名>]…)]AS<子査询>

[WITH CHECK OPTION];

其中,子査询可以是任意复杂的SELECT语句,但通常不允许含有ORDER BY子句和DISTINCT短语。WITH CHECK OPTION表示对视图进行UPDATE、INSERT和DELETE操作时要保证更新、插入或删除的行满足视图定义中的谓词条件(即子査询中的条件表达式)。

组成视图的属性列名或者全部省略,或者全部指定,没有第3种选择。如果省略了视图的各个属性列名,则隐含该视图由子査询中SELECT子句目标列中的诸字段组成。

2)示例


CREATE VIEW clerk AS
SELECT employee_id, last_name, department_id, job_id
FROM employees WHERE job_id = 'PU_CLERK' or job_id = 'SH_CLERK' or job_id = 'ST_CLERK';

(7)删除视图

该语句的格式如下。

DROP VIEW<视图名>;

视图删除后,视图的定义将从数据字典中删除。但是由该视图导出的其他视图定义仍在数据字典中,不过该视图已失效。用户使用时会出错,要用DROP VIEW语句将它们一一删除。

就像基本表删除后,由该基本表导出的所有视图(定义)没有被删除,但均已无法使用了。删除这些视图(定义)需要显式地使用DROP VIEW语句。

(8)査询视图

视图定义后,用户就可以像对基本表一样对视图进行査询了。

DBMS执行对视图的査询时,首先进行有效性检查,检查查询的表、视图等是否存在,如果存在,则从数据字典中取出视图的定义,把定义中的子查询和用户的查询结合起来,转换成等价的对基本表的査询,然后执行修正了的查询。这一转换过程称为视图消解(ViewResolution)。

(9)更新视图

更新视图是指通过视图来插入(INSERT)、删除(DELETE)和修改(UPDATE)数据。由于视图是不实际存储数据的虚表,因此对视图的更新,最终要转换为对基本表的更新。

为防止用户通过视图对数据进行增加、删除、修改时,对不属于视图范围内的基本表数据进行操作,可在定义视图时加上WITH CHECK OPTION子句。这样在视图上增删改数据时,DBMS会检查视图定义中的条件,若不满足条件,则拒绝执行该操作。

3.数据查询

数据库査询是数据库的核心操作。SQL提供了SELECT语句进行数据库的查询,该语句具有灵活的使用方式和丰富的功能。其一般格式如下。

SELECT[ALL|DISTINCT]<目标列表达式>[,<目标列表达式>]...

FROM<表名或视图名> [,<表名或视图名>]...

[WHERE<条件表达式>]

[GROUP BY<列名1>[HAVING<条件表达式]]

[ORDER BY<列名2>[ASC|DESC]];

整个SELECT语句的含义是,根据WHERE子句的条件表达式,从FROM子句指定的基本表或视图中找出满足条件的元组,再按SELECT子句中的目标列表达式,选出元组中的属性值形成结果表。

如果有GROUP子句,则将结果按<列名1>的值进行分组,该属性列值相等的元组为一个组。通常会在每组中使用集函数。如果GROUP子句带HAVING短语,则只有满足指定条件的组才可输出。

如果有ORDER子句,则结果表还要按<列名2>的值的升序(ASC)或降序(DESC)排序。

SELECT语句既可以完成简单的单表査询,也可以完成复杂的连接査询和嵌套查询。

单表查询是指仅涉及一个表的查询。

(1)选择表中的若干列

选择表中的全部列或部分列,这就是投影运算。

·查询指定列。在很多情况下,用户只对表中的一部分属性列感兴趣,这时可以通过在SELECT子句的<目标列表达式>中指定要査询的属性。示例如下。

SELECT son,sname FROM student

查询全体学生的学号和姓名。

·査询全部列。将表中的所有属性列都选出来,可以有两种方法。一种方法就是在SELECT关键字后面列出所有列名。如果列的显示顺序与其在基表中的顺序相同,也可以简单地将<目标列表达式>指定为*。示例如下。


SELECT * FROM student

查询学生表的全部内容。

·查询经过计算的值。SELECT子句的<目标列表达式>不仅可以是表中的属性列,也可以是表达式。示例如下。

SELECT sname,YEAR(NOW( ))-sage AS '出生年份' FROM student

查全体学生的姓名及其出生年份。

(2)选择表中的若干元组

·消除取值重复的行。两个本来并不完全相同的元组,投影到指定的某些列上后,可能变成相同的行了。如果想去掉结果表中的重复行,必须指定DISTINCT短语。示例如下。


SELECT DISTINCT sno FROM sc WHERE grade<90

查询考试成绩小于90分的学生的学号。

·查询满足条件的元组。査询满足指定条件的元组可以通过WHERE子句实现。WHERE子句常用的査询条件如表13-3所示。

表13-3 常用的査询条件

用于进行比较的运算符一般包括=(等于),>(大于),<(小于〉,>=(大于等于),<=(小于等于),!=或<>(不等于),有些产品中还包括!>(不大于),!<(不小于),逻辑运算符NOT可与比较运算符同用,对条件求非。示例:查询所有年龄在20岁以下的学生姓名及其年龄,语句如下。


SELECT sname,sage FROM student WHERE sage<20

谓词BETWEEN…AND…和NOT BETWEEN…AND...可以用来查找属性值在(或不在)指定范围内的元组。示例:查询年龄不在19~20岁之间的学生的姓名、系别和年龄,语句如下。


select sname,sdept,sage from student where sage not between 19 and 20

谓词IN可以用来査找属性值属于指定集合的元组。谓词NOTIN用于査找属性值不属于指定集合的元组。示例:查询信息系(is)、数学系(ma)和计算机科学系(cs)学生的姓名和性别语句如下。


SELECT sname,ssex from student WHERE sdept IN('is','ma','cs')

逻辑运算符AND和OR可用来连接多个查询条件。示例:查询信息系(is)、数学系(ma)和计算机科学系(cs)学生的姓名和性别,语句如下。


SELECT sname,ssex FROM student WHERE sdept='is' OR sdept='ma' OR sdept='cs'

对于字符串进行的最通常的操作是使用操作符like的模式匹配。使用百分号(%)和下划线(_)两个特殊的字符来描述模式。其中百分号匹配任意字符,下划线匹配单个字符。模式匹配对于大小写敏感。字符匹配在SQL中用like来表达。示例:选出客户表中客户所属街道字段含有“吉莲”字样的客户名。


SELECT customer_name FROM customer WHERE customer_street LIKE '%
吉莲%'

·对査询结果排序。用户可以用ORDERBY子句对査询结果按照一个或多个属性列的升序(ASC)或降序(DESC)排序,默认值为升序。示例:查询选修了3号课程的学生的学号及其成绩,查询结果按分数的降序排列,语句如下。


SELECT sno,grade FROM sc WHERE cno='3' ORDER BY grade DESC

·使用集函数。为了进一步方便用户,增强检索功能,SQL提供了许多集函数,如表13-4所示。

表13-4 集函数

如果指定DISTINCT短语,则表示在计算时要取消指定列中的重复值。如果不指定DISTINCT短语或指定ALL短语(ALL为默认值),则表示不取消重复值。

示例:查询学生总人数,语句如下。


SELECT COUNT(*) AS '
总人数' FROM student

示例:查询选修了课程的学生人数,语句如下。


select count(distinct sno) as '
人数' FROM sc

示例:查询选修1号课程的学生最高分数,语句如下。


SELECT MAX(grade) FROM sc WHERE cno='1'

·对査询结果分组。GROUP BY子句将查询结果表按某一列或多列值分组,值相等的为一组。

对査询结果分组的目的是为了细化集函数的作用对象。如果未对查询结果分组,集函数将作用于整个査询结果。如果分组后还要求按一定的条件对这些组进行筛选,最终只输出满足指定条件的组,则可以使用HAVING短语指定筛选条件。

示例:求各个课程号及相应的选课人数,语句如下。


SELECT cno AS '
课程号',COUNT(sno) AS '
人数' FROM sc GROUP BY cno

(3)连接查询

连接是关系数据库模型的特点之一。在SELECT语句的where子句中,通过连接可以实现多表的查询。在关系数据库中,建立表时各表之间的关系不必确定,常把一个实体的所有信息存放在一个表中。当检索时,需要通过连接查询来查询出存在多个表中的不同实体的信息。连接分为简单连接和外连接两种。简单连接使用比较运算符进行表间某(些)列数据的比较操作,并列出这些表中与连接条件相匹配的数据行。进行简单连接时,如果所连接的两个表为同一个表,这种连接又称做自身连接。在表连接查询过程中,如果选择多个表,而不指定其连接条件,那么查询结果将返回这些表的笛卡儿积。

简单连接也称内连接(inner join),简单连接返回符合连接条件的数据行。示例:在学生表和成绩表中查询出学生的姓名、课程号和课程成绩,语句如下。


SELECT s.sname,c.courseid,c.score FROM score AS c
INNER JOIN students AS s ON (c.studentid = s.scode)
或:select students.sname, score.courseid, score.score
FROM students,score WHERE students.scode = score.studentid;

外连接(outer join)不仅返回符合连接条件的数据行,而且还返回某(些)表的所包含的所有其他数据,对应没有数据的表将是空。外连接有左外连接(left outer join)、右外连接(right outer join)、全外连接(full outer join)。

·如果A表左外连接B表,那么查询结果将返回所有的A表的记录,对应选出B表的字段中没有匹配上的行将为空。示例:要统计所有学员的考试情况,要求显示所有参加考试学员的每次考试分数,没有参加考试的学员也要显示出来,语句如下。


SELECT s.sname, c.courseid,c.score
FROM students as s
LEFT OUTER JOIN score AS c ON s.scode = c.studentid;

·如果A表右外连接B表,那么查询结果将返回所有B表的记录,对应选出A表的字段中没有匹配上的行将为空。

·如果A表全连接B表,那么查询结果将返回所有的A表和B表的记录,对应选出A表的字段中没有匹配上的行将为空,对应选出B表的字段中没有匹配上的行也将为空。

(4)嵌套查询

在SELECT语句的where子句中又出现一个select语句,这种查询称为嵌套查询。其中,where子句中出现的SELECT查询称为子查询。嵌套查询的目的主要有以下几点。

判断某条记录是否在某个记录集中,这个记录集由SELECT语句产生。连接词in用于测试where条件中某(些)字段的取值在由select子句产生的一组取值的集合中,反之则用notin。示例:找出手机用户是VIP用户的所有信息,语句如下。


SELECT * FROM table_user WHERE mobile_number IN (SELECT mobile_number FROM table_vip);

反之找出手机用户中不是VIP用户的用户的所有信息为,语句如下。


SELECT * FROM table_user WHERE mobile_number NOT IN (SELECT mobile_number FROM table_vip);

另外,利用连接查询,也可以取得上述查询要求。如找出手机用户是VIP用户的所有信息利用连接查询的语句如下。


SELECT A.* FROM table_user as A ,table_vip B WHERE A.mobile_number=B.mobile_number;

这个例子说明,实现同样一个查询功能,在SQL语句中,可以有不同的实现方法,这样可以比较灵活地使用户选择最适合自己的方法。

判断主查询中确定的where条件指定的记录集中的任一条记录与子查询的所有记录进行的数值比较。连接词some(或any)、all,用于在SQL语句中实现该查询功能。some的意义是“至少比其中一个”,all的意义是“比所有的”,它们接上比较操作符就可以有如下意义。

·>some:至少比其中一个大。

·< li="">

·=some:至少是其中一个的值,其意义等同于in连接词。

·>=some:至少不小于其中一个。

·<=some:至少不大于其中一个。

·<>some:至少有一个值不等于其中的一个,其意义不等于notin连接词。

·all连接词与some类似也可以允许与上述操作符结合,形成不同的比较意义。示例:查询出手机用户中那些至少比VIP用户其中一个总话费高的所有手机用户的信息,语句如下。


SELECT * FROM table_user WHERE total_charge>SOME(SELECT total_charge FROM table_vip);

用连接方法实现,该语句也可以写为如下格式。


SELECT A.* FROM table_user A ,table_vip B WHERE A.total_charge>B.total_charge;

再如:查询出手机用户中那些比所有VIP用户的总话费都高的所有用户的信息,语句如下。


SELECT * FROM table_user WHERE total_charge>ALL(SELECT total_charge FROM table_vip);

·连接词exists用于实现该查询功能。exists存在,则条件为真;not exists不存在,则条件为假。示例:一个VIP手机用户肯定是一个手机用户,在用户表中查询所有的VIP,用户,语句如下。


SELECT user_name FROM table_user where
EXISTS(SELECT * FROM table_vip WHERE table_vip.mobile_number=table_user.mobile_number);

·连接词unique用于实现该查询功能。unique所有元组唯一,则为真;not unique有元组重复,则为真。示例:查询出手机用户中只有一个缴费账户的手机用户信息,语句如下。


SELECT * FROM table_user AS A WHERE UNIQUE(SELECT B.account_name FROM table_account B
WHERE A.mobile_number=B.mobile_number);

(5)集合操作

关系代数中的运算符“∪”、“∩”、“-”对应了集合的并、交、差运算,在SQL语句中我们用union、intersect、except连接词来进行操作。

·SQL查询中用union来实现并操作。union操作将自动去除重复记录,union all则保留重复记录。示例:找出银行中有存款或贷款账户的所有客户,语句如下。


(SELECT customer_name FROM depositor)
UNION
(或UNION ALL
)
(SELECT customer_name FROM borrower)

·SQL查询中用intersect来实现交操作。intersect操作将自动去除重复记录,intersect all则保留重复记录。示例:找出银行中既有存款又有贷款账户的所有客户,语句如下。


(SELECT customer_name FROM depositor)
INTERSECT
(或INTERSECT ALL
)
(SELECT customer_name FROM borrower)

·SQL查询中用except来实现差操作。except操作将自动删除重复记录,except all则保留重复记录。示例:找出银行中有存款账户而没有贷款账户的所有客户,语句如下。


(SELECT customer_name FROM depositor)
EXCEPT
(或EXCEPT ALL
)
(SELECT customer_name FROM borrower)

4.数据更新

SQL中数据更新包括插入数据、修改数据和删除数据3条语句。

(1)插入数据

SQL的数据插入语句INSERT通常有两种形式,一种是插入一个元组;另一种是插入子査询结果。后者可以一次插入多个元组。

插入单个元组的INSERT语句的格式如下。

INSERT INTO<表名>[(<属性列1>[,<属性列2>]...)]

VALUES(<常量1>[,<常量2>]...);

其功能是将新元组插入指定表中。其中,新记录属性列1的值为常量1,属性列2的值为常量2,等等。INTO子句中没有出现的属性列,新记录在这些列上将取空值。但必须注意的是,在表定义时说明了NOTNULL的属性列不能取空值,否则会出错。如果INTO子句中没有指明任何列名,则新插入的记录必须在每个属性列上均有值。

示例:往表departments中插入一条记录,其中对应departments的所有字段都有值,语句如下。


INSERT INTO departments
VALUES (280, 'Recreation', 121, 1700);

子查询不仅可以嵌套在SELECT语句中,用以构造父查询的条件,也可以嵌套在INSERT语句中,用以生成要插入的批量数据。插入子査询结果的INSERT语句的格式如下。

INSERT INTO<表名>[(<属性列1>[,<属性列2...])子査询;

示例:往bonuses表中插入由表employees中按条件commission_pct>0.25*salary选出的所有记录,语句如下。


INSERT INTO bonuses
SELECT employee_id, salary*1.1 FROM employees
WHERE commission_pct > 0.25 * salary;

(2)修改数据

修改操作语句的一般格式如下。

UPDATE<表名>SET<列名>=<表达式>[,<列名>=<表达式>]...[WHERE<条件>];

其功能是修改指定表中满足WHERE子句条件的元组。其中,SET子句给出<表达式>的值用于取代相应的属性列值。如果省略WHERE子句,则表示要修改表中的所有元组。

示例:把State_cd为MA的客户的sales改为0,语句如下。


UPDATE customer SET sales = 0 WHERE state_cd='MA';

(3)删除数据

删除语句的一般格式如下。

DELETE FROM<表名>[WHERE<条件>];

DELETE语句的功能是从指定表中删除满足WHERE子句条件的所有元组。如果省略WHERE子句,表示删除表中全部元组,但表的定义仍在字典中。

示例:把State_cd为MA的客户记录从表中删除,语句如下。


DELETE FROM customer WHERE state_cd='MA';

5.完整性控制与安全机制

完整性控制与安全机制都是一种用于防止数据库数据被破坏或查看的措施。完整性控制主要强调在数据库数据间自身对某些既定规则的约束和遵守,而安全机制主要强调外界在访问数据库中的数据时对其各种行为操作的资源是否具有权限的一种防护。

(1)完整性控制

数据库中的完整性控制可以由应用程序编写程序来实现数据自己的完整性,也可以通过数据库自带完整性约束来实现。用完整性约束来实现数据的完整性比用应用程序来进行完整性控制更可靠更高效。完整性约束是用一些规则来限制在一个表中的某(些)列,是一种保证数据库数据一致性和有效性的一种手段。完整性约束语句一般出现在创建表(视图)或修改表(视图)语句中,用于影响列的定义和某些条件的定义。完整性控制按照完整性约束是否具有修复数据能力分为两大类:声明型完整性约束和处理型完整性约束。

声明型完整性约束是指通过使用声明性的约束子句在DDL语句中声明了约束,一旦违反约束的数据操作发生后,只需由系统简单地对该数据操作进行禁止。声明型完整性约束主要分为:域完整性约束、参照完整性约束、全局约束。其中,域完整性约束又分为非空值约束(Not Null Constraint)和检查约束(Check Constraint),参照完整性约束主要有主键约束(Primary Key Constraint)、唯一性约束(Unique Constraint,又称候选键约束)、外键约束(ForeignKey Constraint)。

处理型完整性约束是指在约束的定义过程中,不仅声明了某个约束,而且这个约束的具体规则及处理行为系统并没有实现,需要约束本身用代码来实现。实现后的约束具有很多灵活性,而不是简单地对数据操作做禁止与允许处理。从维护数据完整性的意义上看,处理型的完整性约束是应用程序维护数据完整性的一种特例,不同的是在维护数据完整性的时候约束是系统强制执行的,而应用程序是由用户自定义执行的。常用的处理型完整性约束主要是触发器(trigger)。处理型完整性约束同声明型完整性约束相比,能够实现更为复杂的检查和操作,从而保证数据库数据的一致性。但是,因为触发器很容易造成级联调用,而且实现相同的约束效率要比声明型约束差,应合理利用而不能滥用。

1)非空约束

非空是个规则,是对声明了非空约束的字段限制其取值域不能为空。它不允许在对一列的数据插入或更新时取NULL值。在默认情况下,是所有的列都允许填充NULL值的,只有在列声明了非空值的列值或其他已经包含了非空值约束的列值时,系统强制要求任何时候都不能填充NULL值。非空约束通常会包含在相关的其他约束上,如主键约束、候选键约束等。因为索引是不对NULL值进行存储的,所以,如果希望使用索引进行表数据的查询,那么必须尽量地使某个要索引的列不包含NULL值。

例如如下语句可以对emp表的ename字段声明非空约束。创建表时,语句如下。


CREATE TABLE emp (
ename VARCHAR(32) NOT NULL,
emanager VARCHAR(30),
…);

修改表时,语句如下。


Alter table emp modify ename not null;

对于表emp,如果已经有了数据,而且ename列中已存在NULL值,则该操作将被禁止。只要将空值替换或将对应的行删除,该语句还是可以被允许的。当然对于不明确的列但又不能为空时,可以使用默认值(default)对列值做默认处理,这样也可以远离NULL值对列的影响。

2)检查约束

相对于非空约束,检查约束能更灵活地限制某字段取值的值域,客观地说,非空约束是检查约束的一个特例而已。检查约束需要涉及一个表达式,某条记录的某(些)字段的值,如果使这个表达式为假,则这条记录被禁止,反之则被允许。如果定义一个检查约束涉及一个某字段不为空的表达式,那么效果就跟非空约束一样了。检查约束涉及的表达式具体应用到某条将要进行操作的记录的某(些)字段时,只有3个值——true、false、unknown,表达式值为false时将要进行的操作被禁止,其他的则允许。在检查约束的表达式中,有如下要求。

·该表达式在使用数据插入或更新操作的值时,必须是可以做出逻辑判断的表达式。

·该表达式不可以使用嵌套查询和序列器。

·该表达式不可以使用SQL函数。

·该表达式不可以使用自定义函数。

·该表达式不可以使用DBMS的伪字段(比如Oracle中的rownum、level等)。

如下语句说明如何在创建表的语句中声明检查约束。


CREATE TABLE Dept_tab (
Deptno NUMBER(3),
Dname VARCHAR2(15),
Loc VARCHAR2(15),
CONSTRAINT Loc_check1
CHECK (loc IN ('
北京', '
上海', '
广州')));

该语句为表Dept_tab中的Loc字段声明了名为Loc_check1的CHECK约束,这个约束要求Loc字段只能填写(‘北京’,‘上海’,‘广州’)值中的一个,否则操作将被禁止。

3)主键约束

主键是能唯一标识元组的最小属性集,并且是在数据库中被标记为primarykey的属性集。如果某个表的某(些)字段声明为主键,那么这些字段就接受了要遵守如下两条规则。

·在这些作为主键的字段中任何字段任何行都不能为空。

·在这些作为主键的字段中任何两行之间的组合取值不能重复。

如下语句是在创建表的语句中声明主键约束。


CREATE TABLE dept (
deptno NUMBER PRIMARY KEY,
dname VARCHAR2 (30)
);

该语句在表dept中声明了字段deptno为该表的主键,这个主键约束并未命名,它的名称可以由系统自动产生。再看下面的语句:


CREATE TABLE emp (
empno NUMBER,
ename VARCHAR2 (30),
CONSTRAINT epk PRIMARY KEY (empno));

该语句在表emp中声明了字段empno为主键,同时命名该主键约束为epk。

每个表都可以有一个主键,只要能唯一标识每一行的数据而且不为空的字段或字段集都可以做主键。理论上是这样,但是实际上,在选择主键时尽量遵守以下原则。

·尽量使用一自动数值序列类型的字段做主键。

·尽量避免一个主键由多个字段组合的情况。

·尽量选择数据很少更新的列做主键。

·尽量选择数值数据或其他占用空间更小的列作为主键。

4)候选键约束

能唯一标识元组的最小属性集,但在数据库中未被标记为primary key,这样的属性集我们称为候选键。这里的候选键实质就是唯一性约束。它的规则要求与主键的规则要求一样,只是未被声明为主键而已。下列语句在创建表中声明了候选键约束。


CREATE TABLE emp (
empno NUMBER,
ename VARCHAR2 (30),
CONSTRAINT euk UNIQUE KEY (empno));

该语句为表emp的empno字段声明了一个叫euk的唯一性约束。

5)外键约束

外键是能在另一关系模式中唯一标识该实体的元组的属性集,存在于本关系模式中。对于本关系模式来说,这些属性集称为相对于另一关系模式的外键。通常外键在数据库中会被标记为foreign key字样。这里我们称另一关系模式为父模式,本关系模式为子模式。通俗地说就是父表中的主键字段被子表中某个字段引用,那么子表的这个字段,则应声明为外键,而父表的那个字段可以声明为主键也可以声明为唯一键(候选键)。一旦子表的字段被声明为父表的外键,同样的一个字段在父表中称为引用的父键,在子表中称为引用的子键。子键的取值应遵守如下规则,否则将被禁止。

·每个子键的取值不能取父键中取值以外的值,但空除外。

·对于父键是组合字段的,子键也应是组合字段,父键要求能唯一地标识父表的每一条记录,而子键不要求能唯一标识子表的每一条记录。

·对于组合键,子键为空时,所有的键的成员字段都为空,不允许部分为空。

一个子表可以有多个子键,每个子键可以对应不同父表的父键。如果是组合键,那么,同一个字段可能作为不同的外键的成员。当然,子表和父表是相对的,子表如果有唯一键被其他表引用,那么这时的子表对于其他表关于某键,它又是父表。外键的引入,主要是为了表示表间的一对多问题。下面的语句说明了两个表间的外键引用情况。


CREATE TABLE dept (
deptno NUMBER PRIMARY KEY,
dname VARCHAR2 (30));
CREATE TABLE emp (
empno NUMBER,
ename VARCHAR2 (30),
deptno NUMBER REFERENCES (dept),
CONSTRAINT efk FOREIGN KEY (deptno)
REFERENCES (dept.deptno) DEFERRABLE);

这两条语句创建了dept和emp两个表,其中,dept表中的deptno是它的主键,它被表emp引用,在emp中也有个同样名字的deptno字段,这个字段被声明为引用dept.deptno字段的外键。那么dept表是父表,deptno构成了引用中父表的父键,emp表是子表,deptno构成了引用中子表的子键。

因为外键是引用父表父键的子表的子键,所以父表的数据是引用的基础。一旦父表数据被修改或删除,引用也会造成相关的影响,表现在子表和子键上,这就需要做出相应的规则来约定父表父键发生改动后子表子键如何来进行维护活动。根据这种活动,可以将子表的外键分为3大类。

·禁止更新和删除父键,许多DBMS默认为这一类外键约束。一旦父表的父键被某个子表的子键引用了,那么父表中已有的数据是禁止修改和删除的。

·删除或更新父表数据的同时删除或更新子表子键中对应父键取值的行。

·删除或更新父表数据的同时将子表中对应父键的子键的取值设置为NULL。

加入这3种外键约束声明的语句可以如下。


CREATE TABLE Emp_tab (FOREIGN KEY (Deptno) REFERENCES Dept_tab);

该语句说明外键deptno默认为第一类。


CREATE TABLE Emp_tab (
FOREIGN KEY (Deptno) REFERENCES Dept_tab
ON DELETE CASCADE);

该语句声明一个第二类的外键。


CREATE TABLE Emp_tab (
FOREIGN KEY (Deptno) REFERENCES Dept_tab
ON DELETE SET NULL);

该语句声明一个第三类的外键。

(2)安全机制

某个用户对某类数据具有何种操作权力是个政策问题而不是技术问题。数据库管理系统的功能是保证这些决定的执行。为此DBMS必须具有以下功能。

·把授权的决定告知系统,这是由SQL的GRANT和REVOKE语句来完成的。

·把授权的结果存入数据字典。

·当用户提出操作请求时,根据授权情况进行检査,以决定是否执行操作请求。

1)授权

SQL用GRANT语句向用户授予操作权限,GRANT语句的一般格式如下。


GRANT <
权限> [,<
权限>]...
[ON <
对象类型> <
对象名>] TO <
用户> [,<
用户>]...
[WITH GRANT OPTION];

其语义为将对指定操作对象的指定操作权限授予指定的用户。

示例:将对供应商S、零件P以及项目J的所有操作权限赋给用户U1及U2,语句如下。


GRANT ALL PRIVILEGES ON TABLE S, P, J TO U1, U2

DBA把数据库SPJ中建立表的权限赋给用户U1,语句如下。


GRANT CREATE TABLE ON DATABASE SPJ TO U1

将对供应商S的插入权限赋给用户U1,并允许将此权限赋给其他用户,语句如下。


GRANT INSERT ON TABLE s TO U1 WITH GRANT OPTION

2)收回权限

授予的权限可以由DBA或其他授权者用REVOKE语句收回,REVOKE语句的一般格式如下。


REVOKE <
权限> [,<
权限>]...
[ON <
对象类型> <
对象名>]
FROM <
用户>[,<
用户>];

示例:将用户U1及U2对供应商S、零件P和项目J的所有操作权限收回,语句如下。


REVOKE ALL PRIVILEGES ON TABLE S, P, J FROM U1, U2

将所有用户对供应商S的所有查询权限收回,语句如下。


REVOKE SELECT ON TABLE S FROM PUBLIC

将U1用户对供应商S的供应商编号Sno的修改权限收回,语句如下。


REVOKE UPDATE ON TABLE S (Sno) FROM U1

SQL提供了非常灵活的授权机制。DBA拥有对数据库中所有对象的所有权限,并可以根据应用的需要将不同的权限授予不同的用户。

教程类别