第4章 中级SQL

1.连接表达式

对于studenthetakes两个关系:

student关系

ID name dept_name tot_cred
00128 Zhang Comp.Sci 102
12345 Shankar Comp.Sci. 32
19991 Brandt History 80
23121 Chavez Finance 110
44553 Peltier Physics 56
45678 Levy Physics 46
54321 Wiliams Comp.Sci. 54
55739 Sanchez Music 38
70557 Snow Physics 0
76543 Brown Comp.Sci. 58
76653 Aoi Elec.Eng. 60
98765 Bourikas Elec.Eng. 98
98988 Tanaka Biology 120

takes 关系

ID course.id sec_id semester year grade
00128 CS-101 1 Fall 2009 A
00128 CS-347 1 Fall 2009 A-
12345 CS-101 1 Fall 2009 c
12345 CS-190 2 Spring 2009 A
12345 CS-315 1 Spring 2010 A
12345 CS-347 1 Fall 2009 A
19991 HIS-351 1 Spring 2010 B
23121 FIN-201 1 Spring 2010 C+
44553 PHY-101 1 Fall 2009 B-
45678 CS-101 1 Fall 2009 F
45678 CS-101 1 Spring 2010 B+
45678 CS-319 1 Spring 2010 B
54321 CS-101 1 Fall 2009 A-
54321 CS-190 2 Spring 2009 B+
55739 MU-199 1 Spring 2010 A-
76543 CS-101 1 Fall 2009 A
76543 CS-319 2 Spring 2010 A
76653 EE-181 1 Spring 2009 C
98765 CS-101 1 Fall 2009 C-
98765 CS-315 1 Spring 2010 B
98988 BIO-101 1 Summer 2009 A
98988 BlO-301 1 Summer 2010 null

1.1 连接关系

SQL支持另一种形式的连接,其中可以指定任意的连接条件。

on条件允许在参与连接的关系上设置通用的谓词。该谓词的写法与where子句谓词类似,只不过使用的是关键词on而不是where,与using条件一样,on条件出现在连接表达式的末尾。

select *
from student join takes on student.ID = takes.ID;

表明:如果student元组的ID与takes的元素ID上取值一样,那么就是匹配的。

其实上述的查询与以下的查询是等价的:

select *
from student, takes
where student. ID=takes. ID;

关系名用来区分属性名ID,这样的ID的两次出现分别表示为student.ID和takes.ID,只显示一次ID值的查询版本如下:

select student. ID as ID, name, dept_name, tol_cred, course_id, sec_id, semester, year, grade
from student join takes on student. ID=takes. ID;

查询的结果如下

ID name dept_name tot_cred course_id sec_id semester year grade
[00128 Zhang Comp.Sci 102 CS-101 1 Fall 2009 A
00128 Zhang Comp.Sci. 102 CS-347 1 Fall 2009 A-
12345 Shankar Comp.Sci. 32 CS-101 1 Fall 2009 C
12345 Shankar Comp.Sci. 32 CS-190 2 Spring 2009 A
12345 Shankar Comp.Sci. 32 CS-315 1 Spring 2010 A
12345 Shankar Comp.Sci. 32 CS-347 1 Fall 2009 A
19991 Brandt History 80 HIS-351 1 Spring 2010 B
23121 Chavez Finance 110 FIN-201 1 Spring 2010 C+
44553 Peltier Physics 56 PHY-101 1 Fall 2009 B-
45678 Levy Physics 46 CS-101 1 Fall 2009 F
45678 Levy Physics 46 CS-101 1 Spring 2010 B+
45678 Levy Physics 46 CS-319 1 Spring 2010 B
54321 Williams Comp.Sci. 54 CS-101 1 Fall 2009 A-
54321 Williams Comp.Sci. 54 CS-190 2 Spring 2009 B+
55739 Sanchez Music 38 MU-199 1 Spring 2010 A-
76543 Brown Comp.Sci. 58 CS-101 1 Fall 2009 A
76543 Brown Comp.Sci. 58 CS-319 2 Spring 2010 A
76653 Aoi Elec.Eng. 60 EE-181 1 Spring 2009 C
98765 Bourikas Elec.Eng. 98 CS-101 1 Fall 2009 C-
98765 Bourikas Elec.Eng. 98 CS-315 1 Spring 2010 B
98988 Tanaka Biology 120 BIO-101 1 Summer 2009 A
98988 Tanaka Biology 120 BIO-301 1 Summer 2010 null

on条件可以表示任何SQL谓词,从而使用on条件的连接表达式比自然连接更加丰富的连接条件。

1.2 外连接

下面的查询好像能够检索出所需的信息

select *
from student natural join takes;

但是如果有一些学生,如果没有选修任何课程,那么student关系中所对应的元素与takes关系中的任何元组配对,就不会满足自然连接的条件。这样我们就不能看到这些学生。

更为一般地,在参与连接的任何一个或两个关系中的某些元组可能会以这种方式“丢失”。外连接(outer join) 运算与我们已经学过的连接运算类似,但通过在结果中创建包含空值元组的方式,保留了那些在连接中丢失的元组。

外连接有三种形式:

  • 左外连接(left outer join):只保留出现在左外连接运算之前(左边)的关系中的元组。
  • 右外连接(right outer join):只保留出现在右外连接运算之后(右边)的关系中的元组。
  • 全外连接(full outer join):保留出现在两个关系中的元组。

而此前不保留未匹配的元素的方式称为内连接(inner join)运算

那么具体的形式左外连接运算:首先,像外面那样计算出内连接的结果,然后,对于在内连接的左侧关系中任意一个与右侧关系中任何元素都不匹配的元素t,向连接结果中加入一个元组r。r的构造如下:

  • 元组r从左侧关系得到的属性被赋为t中的值。
  • r的其他属性被赋值为空值。

左外连接例子

select *
from student natural leftt outer join lakes;
ID name dept_name tot_cred course_id sec_id semester year grade
[00128 Zhang Comp.Sci. 102 CS-101 1 Fall 2009 A
00128 Zhang Comp.Sci. 102 CS-347 1 Fall 2009 A-
12345 Shankar Comp.Sci. 32 CS-101 1 Fall 2009 C
12345 Shankar Comp.Sci. 32 CS-190 2 Spring 2009 A
12345 Shankar Comp.Sci. 32 CS-315 1 Spring 2010 A
12345 Shankar Comp.Sci. 32 CS-347 1 Fall 2009 A
19991 Brandt History 80 HIS-351 1 Spring 2010 B
23121 Chavez Finance 110 FIN-201 1 Spring 2010 C+
44553 Peltier Physics 56 PHY-101 1 Fall 2009 B-
45678 Levy Physics 46 CS-101 1 Fall 2009 F
45678 Levy Physics 46 CS-101 1 Spring 2010 B+
45678 Levy Physics 46 CS-319 1 Spring 2010 B
54321 Williams Comp.Sci. 54 CS-101 1 Fall 2009 A-
54321 Williams Comp.Sci. 54 CS-190 2 Spring 2009 B+
55739 Sanchez Music 38 MU-199 1 Spring 2010 A-
70557 Snow Physics 0 nmull mull null null null
76543 Brown Comp.Sci. 58 CS-101 1 Fall 2009 A
76543 Brown Comp.Sci. 58 CS-319 2 Spring 2010 A
76653 Aoi Elec.Eng. 60 EE-181 1 Spring 2009 C
98765 Bourikas Elec.Eng. 98 CS-101 1 Fall 2009 C-
98765 Bourikas Elec.Eng. 98 CS-315 1 Spring 2010 B
98988 Tanaka Biology 120 BIO-101 1 Summer 2009 A
98988 Tanaka Biology 120 BIO-301 1 Summer 2010 null

on子句可以和外连接一起使用。下述查询与我们见过的第一个使用“student natural left outer join takes"的查询是相同的,只不过属性ID在结果中出现两次。

select *
from student left outer join takes on student.ID=takes.ID;

on和where在外连接中的表现是不一样的。原因是外连接之为那些对应内连接结果没有贡献的元组补上空值并加入结果。on条件是外连接声明的一部分,但是where子句却不是。

1.3 连接类型和条件

SQL中的常规连接称作内连接。这样连接子句就可以用inner join来替换outer join .说明使用的是常规连接,关键词inner是可选的,当join子句中没有使用outer前缀,默认的连接类型是inner join。

2. 视图

我们一直在逻辑模型层操作,即我们假定了给定的集合的关系都是实际存储在数据库中。让所有用户都看到整个逻辑模型是不合适的。但是出于安全考虑,可能需要向用户隐层特定的数据。

select ID,name,dept_name
from instructor;

我们还可能希望创建一个比逻辑模型更加符合特定用户直觉的个性化的关系集合。

select course. course id, sec-id, building, room_number
from course, section
where course. course_id =section. course_id and course. dept_name =' Physics'and section. semester=' Fall'and section. year ='2009';

如果我们将计算出的上述结果存储下来,并传递给用户,但是如果底层关系发生变化,那么结果就匹配。

在SQL中允许通过查询定义“虚关系”,它在概念上包含查询结果。虚关系不预先计算并存储,而是使用虚关系的时候才通过执行查询被计算出来。

任何想这种不是逻辑模型的一部分,但作为虚关系对用户可见的关系称为视图(view)。任何给定的实际关系集合上能够支持大量视图。

2.1 视图的定义

可以使用create view命令定义视图。

create view命令的格式为

create view v as< query expression>;

其中<query expression>可以是任何合法的查询表达式,v表示视图名。

create view faculty as
select ID,name,dept_name
from instructor;

正如前面已经解释过的,视图关系在概念上包含查询结果中的元组,但并不进行预计算和存储。相反,数据库系统存储与视图关系相关联的查询表达式。当视图关系被访问时,其中的元组是通过计算查询结果而被创建出来的。从而,视图关系是在需要的时候才被创建的。

视图:列出Physics系在2009年秋季学期所开设的所有课程段,以及每个课程段在那栋建筑的那个房间授课的信息

create view physics_fall_2009 as select course, course_id, sec_id, building, room _number from course, section where course.course_id= section.course_id and course. dept_name=' Physics'and section. semester=' Fall'and section. year='2009';

2.2 SQL查询中使用视图

一旦定义了一个视图,就可以用视图名指代该视图生成的虚关系。

查询找到所有于2009年秋季学期在Watson大楼开设的Physics课程

select course_id
from physics_fall_2009
where building='Watson';

在查询中,视图名可以出现在关系名可以出现的任何地方

视图的属性名可以按下述方式显式指定:

create view departments_total_salary(dept_name,total_salary)as
select dept_name,sum(salary)
from instructor
group by dept_name;

因为sum表达式没有名称,其属性名在视图定义中显式指定的。

无论何时执行这个查询,视图关系都被重新计算

一个视图可能被用到定义另一个视图的表达式中。例如,我们可以如下定义视图 physics_fall_2009_watson,它列出了于2009年秋季学期在Watson大楼开设的所有Physics 课程的标识和房间号:

create view physics_fall_2009_watson as
select course_id,room_number
from physics fall_2009
where building='Watson';

等价于:

create view physics_fall_2009_watson as(select course_id, room_number from(select course.course_id, building, room_numberfrom course, sectionwhere course.course_id = section.course_id and course.dept_name=' Physics'and section.semester=' Fall'and section.year='2009')where building=' Watson';

2.3 物化视图

特定数据库系统允许存储视图关系,但是它们保证:如果用于定义视图的实际关系改变,视图也跟着修改。这样的视图被称为物化视图(materialized view)

保持物化视图一直在最新状态的过程称为物化视图维护(materialized view maintenance)。或者通常简称视图维护(view maintenance)

当构成视图定义的任何关系被更新时,可以马上进行视图维护。然而某些数据库系统在视图被访问时才执行视图维护。还有一些系统仅采用周期性的物化视图更新方式,在这种情况下,当物化视图被使用时,其中的内容可能是陈旧的,或者说过时的。如果应用需要最新数据的话,这种方式是不适用的。某些数据库系统允许数据库管理员来控制在每个物化视图上需要采取上述的哪种方式。

2.4 视图更新

一般来说,如果定义视图的查询对下列条件都能满足,我们称SQL视图是可更新的(updatable)

  • from子句中只有一个数据库关系
  • select子句中只包含关系的属性名,不包含任何表达式、聚集或distinct声明。
  • 任何没有出现在select子句的属性可以取空值,即这些属性没有not null约束,也不构成主码一部分。
  • 查询不包含有group by或having子句。

在这些限制下,下面的视图上允许执行update、insert和delete操作。

create view history_instructors as
select *
from instructor where dept_name='History';

在默认情况下,SQL允许执行上述更新。但是,可以通过在视图定义的末尾包含with check option子句的方式来定义视图。这样,如果向视图中插入一条不满足视图的where子句条件的元组,数据库系统将拒绝该插入操作。类似地,如果新值不满足where子句的条件,更新也会被拒绝。

3. 事务

**事务(transaction)**由查询和(或)更新语句的序列组成。SQL标准规定当一条SQL语句被执行,就隐式地开始了一个事务。下列SQL语句之一会结束一个事务:

  • Commit work:提交当前事务,也就是将该事务所做的更新在数据库中持久存储,事务被提交后,一个新的事务自动开始
  • Rollback work:回滚当前事务,即撤销该事务中的所有SQL语句对数据库的更新,这样数据库就恢复到执行该事务第一条语句之前的状态。

关键词work在两个语句中都是可选的。

一个事务或者在完成所有步骤后提交其行为,或者在不能成功完成其所有动作的情况下回滚其所有动作,通过这种方式数据库提供了对事务具有原子性(atomic) 的抽象,原子性也就是不可分割性。要么事务的所有影响被反映到数据库中,要么任何影响都没有(在回滚之后)。

如果程序没有执行两条命令中的任何一条而终止了,那么更新要么被提交要么被回滚。SQL标准并没有指出究竟执行哪一种,如何选择依赖于具体实现。

在很多SQL实现中,默认方式下每个SQL语句自成一个事务,且一执行完就提交。如果一个事务要执行多条SQL语句,就必须关闭单独SQL语句的自动提交。如何关闭自动提交也依赖于特定的SQL实现,尽管在诸如JDBC或ODBC那样的应用编程接口中存在标准化方式来完成这项工作。

4. 完整性约束

完整性约束保证授权用户对数据库所做的修改不会破坏数据的一致性。因此,完整性约束防止的是对数据的意外破坏。

完整性约束的例子有:

  • 教师姓名不能为null。
  • 任意两位教师不能有相同的教师标识。
  • course 关系中的每个系名必须在department关系中有一个对应的系名。
  • 一个系的预算必须大于0.00美元。

完整性约束通常被看成是数据库模式设计过程的一部分,它作为用于创建关系的create table命令的一部分被声明。然而,完整性约束也可以通过使用alter table table-name add constraint命令施加到已有关系上,其中constraint可以是关系上的任意约束。当执行上述命令时,系统首先保证关系满足指定的约束。如果满足,那么约束被施加到关系上;如果不满足,则拒绝执行上述命令。

4.1. 单个关系上的约束

  • not null
  • unique
  • check(<谓词>)

4.2. not null约束

空值是所有域的成员。因此在默认的情况下是SQL中每个属性的合法值。但是在有些情况下,我们并不希望得到的值为空值。

name varchar(20) not null
budget numeric(12,2) not null

not null声明禁止在该属性上插入空值,任何可能导致向一个声明为not null的属性插入空值的数据库都会产生错误的信息。

很多的情况下我们希望避免空值,尤其是SQL禁止在关系模式的主码中出现空值。

4.3. unique约束

SQL还支持下面这种完整性约束:
unique(Aj1,Aj2,⋯,Ajm)unique(A_{j1}, A_{j2},\cdots, A_{jm}) unique(Aj1​,Aj2​,⋯,Ajm​)
unique声明指出Aj1,Aj2,⋯,AjmA_{j1},A_{j2},\cdots,A_{jm}Aj1​,Aj2​,⋯,Ajm​形成了一个候选码,即在关系中没有两个元组能在所有列出的属性上取值相同。

4.4. check子句

当应用于关系声明时,**check§**子句指定一个谓词PPP,关系中的每个的元组都必须满足谓词P。通常用check子句保证属性值满足指定的条件,实际上创建了一个强大的类型系统。

create table section(course_id varchar(8).sec_id varchar(8), semester varchar(6), year numeric(4,0),building varchar(15), room_number varchar(7), time_slot_id varchar(4), primary key(course_id, sec_id, semester, year), check(semester in(' Fall',' Winter',' Spring',' Summer')));

这里check子句模拟了一个枚举类型。

根据SQL标准,check子句中的谓词可以是包括子查询在内的任意谓词。然而,当前还没有一个广泛使用的数据库产品允许包含子查询的谓词。

4.5. 参照完整性

我们常常希望保证在一个关系中给定属性集上的取值也在另一关系的特定属性集的取值中出现。这种情况称为参照完整性(referential integrity)

外码可以用作为SQL中create table 语句一部分的foreign key子句来声明。我们用大学数据库SQL DLL定义的一部分来说明外码声明。course表的定义中有一个声明“foreign key(dept_name)references department”。这个外码声明表示,在每个课程元组中指定的系名必须在department关系中存在。没有这个约束,就可能会为一门课程指定一个不存在的系名。

更为一般的,令关系r1r_1r1​和r2r_2r2​的属性集分别为R1R_1R1​和R2R_2R2​,主码分别为K1K_1K1​和K2K_2K2​。如果要求对r2r_2r2​中任意元组t2t_2t2​,均存在r1r_1r1​中元组t1t_1t1​使得t1.K1=t2.αt_1.K_1 =t_2.\alphat1​.K1​=t2​.α。我们称R2R_2R2​的子集α\alphaα为参考关系r1r_1r1​中K1K_1K1​的外码(foreign key)。

这种要求称为参照完整性约束(referential-intergrity constraint)或子集依赖(subset dependency)。后一种称法是由于上述参照完整性可以表示为这样一种要求:r2r_2r2​中α\alphaα上的取值集合必须是r1r_1r1​中K1K_1K1​上的取值集合的子集。请注意,为使参照完整性约束有意义,α\alphaα 和K1K_1K1​必须是相容的属性集;也就是说,要么α\alphaα 等于K1K_1K1​,要么它们必须包含相同数目的属性,并且对应属性的类型必须相容(这里我们假设α\alphaα 和K1K_1K1​是有序的)。不同于外码约束,参照完整性约束通常不要求K1K_1K1​是r1r_1r1​的主码;其结果是,r1r_1r1​中可能有不止一个元组在属性K1K_1K1​上取值相同。

4.6 事务中对完整性约束的违反

例如,假设我们有一个主码为name的 person关系,还有一个属性是spouse,并且spouse是在person 上的一个外码。也就是说,约束要求 spouse属性必须包含在person表里出现的名字。假设我们希望在上述关系中插入两个元组,一个是关于John的,另一个是关于Mary的,这两个元组的配偶属性分别设置为Mary和John,以此表示John和Mary彼此之间的婚姻关系。无论先插人哪个元组,插入第一个元组的时候都会违反外码约束。在插人第二个元组后,外码约束又会满足了。

为了处理这样的情况,SQL标准允许将inttially deferred子句加入到约束声明中;这样完整性约束不是在事务的中间步骤上检查,而是在事务结束的时候检查。一个约束可以被指定为可延迟的(deferrable),这意味着默认情况下它会被立即检查,但是在需要的时候可以延迟检查。对于声明为可延迟的约束,执行set constraints constraint-list deferred语句作为事务的一部分,会导致对指定约束的检查被延迟到该事务结束时执行。

4.7 复杂check条件与断言

正如SQL标准所定义的,check子句中的谓词可以是包含子查询的任意谓词。如果一个数据库实现支持在check子句中出现子查询,我们就可以在关系section 上声明如下所示的参照完整性约束:

check(time_slot_id in(select time_slot_id from time_slot))

这个check条件检测在section关系中每个元组的time_slot_id的确是在time_slot关系中某个时间段的标识。因此这个条件不仅在section中插入或修改元组时需要检测,而且在time_slot关系改变时也需要检测(如在time_slot关系中,当一个元组被删除或修改的情况下)。

一个断言(assertion) 就是一个谓词,它表达了我们希望数据库总能满足的一个条件。域约束和参照完整性约束是断言的特殊形式。我们前面用大量篇幅介绍了这几种形式的断言,是因为它们容易检测并且适用于很多数据库应用。但是,还有许多约束不能仅用这几种特殊形式来表达。如有两个这样的例子

  • 对于student关系中的每个元组,它在属性tot_cred上的取值必须等于该生所成功修完课程的学分总和。
  • 每位教师不能在同一个学期的同一个时间段在两个不同的教室授课。

SQL中的断言如下形式

create assertion <assertion-name>cheek<predicate>;

由于SQL不提供for all X , P(X)结构,所以我们通过等价的"not exists X such that not P(X)"结构来实现此约束,这一结构可以用SQL来表示。

create asvertion credits_earned_constrainu check(not exists(select ID from student where tot_cred<>(select sum(credits)from takes natural join course where student. ID=takes. ID and grade is not null and grade<>'F');

当创建断言时,系统要检测其有效性。如果断言有效,则今后只有不破坏断言的数据库修改才被允许。如果断言较复杂,则检测会带来相当大的开销。因此,使用断言应该特别小心。

5. SQL的数据类型与模式

5.1 SQL中的日期和时间类型

SQL标准还支持与日期和时间相关的几种数据类型。

  • date:日历日期,包括年(四位)、月和日。
  • time:一天中的时间,包括小时、分和秒。可以用变量time§来表示秒的小数点后数字位数,这里默认为0,通过指定time with timezone,还可以把时区信息连同时间一起存储。
  • timestamp:date和time的组合,可以用变量timestamp§来表示秒的小数点后位数(默认6位)。如果指定with timezone,则时区信息也会被存储。

日期和时间类型的值

date '2001-04-25'
time '09:30:00'
timestamp '2001-04-25 10:29:01.45'

我们可以利用cast e as t形式的表达式来将一个字符串(或字符串表达式)e转换成类型t,其中t是 date、time、timestamp中的一种。字符串必须符合正确的格式,像本段开头说的那样。当需要时,时区信息可以从系统设置中得到。

我们可以利用extract(field from d),从date或time值d中提取出单独的域,这里的域可以是year、month、day、hour、minute 或者 second 中的任意一种。时区信息可以用timezone_.hour和timezone_minute 来提取。

SQL允许在上面列出的所有类型上进行比较运算,也允许在各种数字类型上进行算术运算和比较运算。SQL还支持interval数据类型,它允许在日期、时间和时间间隔上进行计算

5.2 默认值

SQL允许为属性指定默认值,如下面的create table 语句所示:

create table student(ID varchar(5),name varchar(20)not null,dept_name varchar(20),tot_cred numeric(3,0)default0,primary key(ID));

tot_cred属性的默认值被声明为0。

5.3 创建索引

在关系的属性上所创建的索引(index)是一种数据结构,它允许数据库系统高效地找到关系中那些在索引属性上取给定值的元组,而不用扫描关系中的所有元组。

尽管SQL语言没有给出创建索引的正式语法定义,但很多数据库都支持使用如下所示的语法形式来创建索引:

create index studentID_index on student(ID);

上述语句在student关系的属性ID上创建了一个名为studentlD_index的索引。

5.4 大对象类型

许多当前的数据库应用需要存储可能很大(KB级)的属性,例如一张照片;或者非常大的属性(MB级甚至GB级),例如高清晰度的医学图像或视频片断。因此SQL提供字符数据的大对象数据类型(clob) 和二进制数据的大对象数据类型(blob)。在这些数据类型中字符“lob”代表“Large OBject”。
例如,我们可以声明属性

book_reiew clob (10KB)
image blob (10MB)
motvie blob (2GB)

对于包含大对象(好几个MB甚至GB)的结果元组而言,把整个大对象放人内存中是非常低效和不现实的。相反,一个应用通常用一个SQL查询来检索出一个大对象的“定位器”,然后在宿主语言中用这个定位器来操纵对象,应用本身也是用宿主语言书写的。

5.5 用户定义的类型

SQL支持两种形式的用户定义数据类型。第一种称为独特类型(distinct type),另一种称为结构化数据类型(structured data type),允许创建具有嵌套记录结构、数组和多重集的复杂数据类型。

例如用于学生名和教师名的name属性就有可能有相同的域:所有人名的集合。但是如果我们从概念层而不是从屋里层来看待数据库的话,name和dept_name应该有不同域。

更重要的是,在现实中,把一个教师的姓名赋给一个系名可能是一个程序上的错误;类似地,把一个以美元表示的货币值直接与一个以英镑表示的货币值进行比较几乎可以肯定是程序上的错误。一个好的类型系统应该能够检测出这类赋值或比较。为了支持这种检测,SQL提供了独特类型(distinct type) 的概念。

可以用create type子句来定义新类型:

create type Dollars as numeric(12,2) final;
create type Pounds as numeric(12,2) final;

此关键字final并不是真的意义,是SQL:1999标准要求的。

department表定义为:

create table department(depl_name varchar(20),building varchar(15), budget Dollars);

尝试为Pounds类型的变量赋予一个Dollars类型的值会导致一个编译时错误。

由于有强类型检查,表达式(department.budget + 20)将不会被接受。一种类型的数据可以被转换(cast)到另一个域。

cast (department.budget to numeric(12,2))

SQL提供了drop type和 alter type子句来删除或修改以前创建过的类型。

在把用户定义类型加入到SQL之前,SQL有一个相似但是稍有不同的概念:域(domain)可以在基本类型上施加完整性约束。例如

create domain DDollars as numeric(12,2)not null;

DDollars域可以用作属性类型,但是类型和域之间有两个重大差别:

  1. 在域上可以声明约束,然而用户定义类型上不能声明约束或默认值。设计用户定义类型不仅是用它来指定属性类型,而且还将它用在不能施加约束的地方对SQL进行过程扩展。
  2. 域不是强制类型,因此一个域类型的值可以被赋值为另一个域的类型,只要类型是相容的。

5.6 create table的扩展

SQL提供一个create table like来扩展支持这个任务。

create table temp_instructor like instructor;

上述语句创建了一个与instructor具有相同模式的新表temp_instructor。

当书写一个复杂查询时,把查询的结果存储成一个新表是很有用的。

create table tl as(select *from instructor where dept_name='Music')
with data;

一条用于创建表(具有合适的列),另一条用于查询结果插入表中。如果省略with data 子句,表会被创建,但不会被载入数据。

模式、目录与环境

当前数据库系统提供了三层结构的关系命名机制。最顶层由目录(catalog)构成,每个目录都可以包含模式(schema)。诸如关系和视图那样的SQL对象都包含在模式中。

要在数据库上做任何操作,用户(或程序)都必须先连接到数据库。为了验证用户身份,用户必须提供用户名以及密码(通常情况下)。每个用户都有一个默认的目录和模式,这个组合对用户来说是唯一的。当一个用户连接到数据库系统时,将为该连接设置好默认的目录和模式。这对应于当用户登录进一个操作系统时,把当前目录设置为用户的主(home)目录。

为了唯一标识出一个关系,必须使用一个名字,它包含三部分,例如:

catalog5.uniy_shema.course

当名字的目录部分被认为是连接的默认目录时,可以省略目录部分。这样如果catalog5是默认目录,我们可以用univ_schema.course来唯一标识上述关系。

如果用户想访问存在于另外的模式中的关系,而不是该用户的默认模式,那就必须指定模式的名字。然而,如果一个关系存在于特定用户的默认模式中,那么连模式的名字也可以省略。这样,如果catalog5是默认目录并且univ_schema是默认模式,我们可以只用course。

当有多个目录和模式可用时,不同应用和不同用户可以独立工作而不必担心命名冲突。不仅如此,一个应用的多个版本(一个产品版本,其他是测试版本)可以在同一个数据库系统上运行。
默认目录和模式是为每个连接建立的SQL 环境(SQL environment)的一部分。环境还包括用户标识(也称为授权标识符)。所有通常的SQL语句,包括DDL和DML语句,都在一个模式的环境中运行。

6. 授权

我们可能会给一个用户在数据库的某些部分授予几种形式的权限。对数据的授权包括:

  • 授权读取数据。
  • 授权插人新数据。
  • 授权更新数据。
  • 授权删除数据。

每种类型的授权称之为一个权限(privilege)。

当用户提交查询或更新时,SQL执行先基于该用户曾获得过的权限检查此查询或更新是否是授权过的。如果查询或更新没有经过授权,那么将被拒绝执行。

最大的授权形式是被授予数据库管理员的。数据库管理员可以授权新用户、重构数据库,等等。这种权限方式和操作系统中的超级用户、管理员或操作员的权限是类似的。

6.1 权限的授予与收回

SQL标准包括select、insert、update和delete权限。权限所有权限(all privileges)可以用作所有允许权限的简写形式。一个创建了新关系的用户将自动被授予该关系上的所有权限。
SQL数据定义语言包括授予和收回权限的命令。grant 语句用来授予权限。此语句的基本形式为:

grant <权限列表>
on <关系名或视图名>
to <用户/角色列表>;

关系上的select权限用于读取关系中的元组。下面的grant 语句授予数据库用户Amit和Satoshi在department 关系上的select权限:

grant select on department to Amit,Satoshi;

值得注意的是,SQL授权机制可以对整个关系或一个关系的指定属性授予权限。但是,它不允许对一个关系的指定元组授权。
我们使用revoke 语句来收回权限。此语句的形式与grant几乎是一样的:

revoke<权限列表>
on <关系名或视图名>
from<用户/角色列表>;

6.2 角色

角色(role) 的概念适用于此观念。在数据库中建立一个角色集,可以给角色授予权限,就和给每个用户授权的方式完全一样。每个数据库用户被授予一组他有权扮演的角色(也可能是空的)。

另一个不是很合适的方法是建立一个instructor用户标识,允许每位教师用instructor用户标识来连接数据库。该方式的问题是它不可能鉴别出到底是哪位教师执行了数据库更新,从而导致安全隐患。使用角色的好处是需要用户用他们自己的用户标识来连接数据库。

在SQL中创建角色如下所示:

create role instructor;

角色可以授予给用户,也可以授予给其他角色,如这样的语句:

grant dean to Amit;
create role dean;
grant instructor to dean;
grant dean to Satoshi;

一个用户或一个角色的权限包括:

  • 所有直接授予用户/角色的权限。
  • 所有授予给用户/角色所拥有角色的权限。

值得注意的是,基于角色的授权概念并没有在SQL中指定,但在很多的共享应用中,基于角色的授权被广泛应用于存取控制。

6.3 视图的授权

6.4 模式的授权

SQL标准为数据库模式指定了一种基本的授权机制:只有模式的拥有者才能够执行对模式的任何修改,诸如创建或删除关系,增加或删除关系的属性,以及增加或删除索引。

然而,SQL提供了一种references权限,允许用户在创建关系时声明外码。SQL的references权限可以与update权限类似的方式授予到特定属性上。

grant references (dept_name) on department to Mariano;

6.5 权限的转移

获得了某些形式授权的用户可能被允许将此授权传递给其他用户。在默认方式下,被授予权限的用户/角色无权把得到的权限再授予给另外的用户/角色。如果我们在授权时允许接受者把得到的权限再传递给其他用户,我们可以在相应的grant命令后面附加 with grant option子句。

grant select on department to Amit with grant option;

6.6 权限的收回

从一个用户/角色那里收回权限可能导致其他用户/角色也失去该权限。这一行为称作级联收回。在大多数的数据库系统中,级联是默认行为。然而,revoke语句可以申明restrict来防止级联收回:

revoke select on department from Amit,Satoshi restrict;

数据库系统概念笔记——第4章 中级SQL相关推荐

  1. 数据库系统概念笔记——第三章:SQL

    文章目录 第三章:SQL 3.2 SQL数据定义 3.2.1 基本类型 3.2.2 基本模式定义 3.3 SQL查询的基本结构 3.3.1 单关系查询 3.3.2 多关系查询 3.3.3 自然连接 3 ...

  2. 数据库系统概念总结:第四章 中级SQL

    周末无事水文章,期末备考的总结资料 第四章 中级SQL 4.1 连接表达式 4.1.1 连接条件 select * from student join takes on student.ID = ta ...

  3. 数据库系统概念笔记-引言

    转载自 数据库系统概念笔记-引言  作者 CyninMa 数据库系统概念笔记-引言 数据库管理系统(DBMS)由一个互相关联的数据的集合和一组用以访问这些数据的程序组成.这个数据集合通常称作数据库,其 ...

  4. 数据库系统概念笔记-关系模型介绍

    转载自 数据库系统概念笔记-关系模型介绍  作者 CyninMa 数据库系统概念笔记-关系模型介绍 2.1 关系数据库的结构 关系数据库由表(table)的集合构成,每个表有唯一的名字.例如,inst ...

  5. 【数据库系统概念】第14章 事务 知识总结

    <数据库系统概念>第14章知识点总结 事务 事务是访问并可能更新各种数据项的一个程序执行单元.事务通常由高级数据操作语言或编程语言通过JDBC或ODBC嵌入式数据库访问书写的用户程序的执行 ...

  6. 数据库系统概论笔记(第一章 引言)—— 持续更新,争取每周更新一章

    第一章 引言 数据库管理系统(DataBase-Management System, DBMS)*是由一个相互关联的数据的集合和一组用以访问这些数据的程序构成.这个数据集合通常称为数据库(DataBa ...

  7. 数据库系统概念总结:第一章 引言

    周末无事水文章,期末备考的总结资料 第一章 引言 数据库管理系统(DataBase-Management System,DBMS)由一个相互关联的数据的集合和一组用以访问这些数据的程序组成.这个数据集 ...

  8. 【数据库系统概论】第三章:SQL

    B站视频 B站第一章 参考资料 图片来自视频链接和参考资料. 本章目录: SQL特点 SQL基本概念 SQL的基本语法 SQL特点 SQL包括:数据查询.数据操作.数据定义.数据控制 它是一个非过程语 ...

  9. 数据库系统概论笔记整理———第一章(绪论之数据库系统,数据模型,外模式,内模式,层次模型,数据独立性等)

    ❤️ 数据库系统概论 1.数据(data):描述事物的符号记录,可以是数字,图像,音频,视频等. 2.数据的含义称为数据的语义,数据与其语义是不可分的 3.数据库(DB):是长期存储在计算机内,有组织 ...

  10. 数据库系统原理(第四章:SQL与关系数据库基本操作 )

    一.SQL概述 sql是结构化查询语言(Structured Query Language,SQL)是专门用来与数 据库通信的语言,它可以帮助用户操作关系数据库. SQL的特点: SQL不是某个特定数 ...

最新文章

  1. redis的分布式解决方式--codis (转)
  2. 约会安排 (区间合并)毒瘤题
  3. python函数参数*args和**args
  4. 数据结构--环形链表
  5. C++ struct结构体 实现搜索二叉树(BST)
  6. 三个好用的并发工具类
  7. MySQL事务及字符集介绍
  8. 【Elasticsearch】使用Elasticsearch 7.8 快速搭建食谱搜索系统
  9. 继承的原理java_Java继承和多态的原理
  10. 测试基础-01-软件测试的定义与分类
  11. 如何使用无线连接来使Android调试手机
  12. Centos 7 密码重置
  13. 常用端口号及对应服务
  14. [转载] python __import__ 搜索路径详解
  15. 关于STM32F107RCT6使用8M晶振串口波特率错误的问题
  16. Python小白学习第二天
  17. DaaS架构及落地 (一)
  18. elasticsearch OOM
  19. Android组件化实战五: APT的高级用法JavaPoet
  20. 2010.5.11项目管理群主题:网游那些事-DDV731731-SSE

热门文章

  1. 云片网短信服务使用Java
  2. gitlab 版本升级
  3. The Byzantine Generals Problem拜占庭将军问题理解
  4. TeamTalk的windows客户端流程
  5. 触宝发布2018年第四季度财报 净收入增长147%
  6. 最新WIN10系统封装教程2019系列(七)——封装
  7. QIUI囚爱男用APP远程贞操锁2.0 破解不完全指南(附破解工具)
  8. UTC时间与北京时间和纽约的时间
  9. Ubuntu-Chrome 更新Flash插件
  10. pytorch保存模型pth_详解Pytorch中的网络构造,模型save和load,.pth权重文件解析