视图
还是源于老师的ppt
视图是从一个或几个基本表(或视图)导出的表,它与基本表不同,是一个虚表。
视图构建了虚表结构(字段)向基本表的映象。基本表中的数据发生变化,通过视图看到的数据也随之改变。
在数据字典中只存放视图的定义,视图不存储数据。
视图一经定义,就可以和基本表一样被查询和删除,并且可以在视图之上再定义新的视图。
视图的更新(增加、删除、修改)会转换到对基本表的更新,但视图更新会受到一定的限制。
视图对应三级模式/两级映象中体系结构中的外模式和外模式/模式的映象。
(1) 建立视图
语句格式:
CREATE VIEW <视图名> [(<列名> [,<列名>]…)]
AS <子查询>
[WITH CHECK OPTION] ;
注:
CREATE VIEW 子句中的列名可以省略,但在下列情况下明确指定视图的所有列名:
(1) 某个目标列是集函数或列表达式
(2) 多表连接时选出了几个同名列作为视图的字段
(3) 需要在视图中为某个列启用新的更合适的名字
子查询中的属性列不允许定义别名,不允许含有ORDER BY子句和DISTINCT短语。
WITH CHECK OPTION表示对视图进行更新操作的数据必须满足视图定义的谓词条件(子查询的条件表达式)。
建立信息系学生的视图。
CREATE VIEW IS_Student
AS
SELECT Sno, Sname, Sage
FROM Student
WHERE Sdept = 'IS' ;
将学生的学号及他的平均成绩定义为一个视图。
CREATE VIEW S_G (Sno, Gavg)
AS
SELECT Sno, AVG (Grade)
FROM SC
GROUP BY Sno ;
当子查询中有由表达式构成的派生属性列(也称为虚拟列)时,必须明确定义组成视图的各个属性列名。
删除视图
DROP VIEW <视图名> ;
注:
该语句从数据字典中删除指定的视图定义
由该视图导出的其他视图定义仍在数据字典中,但已不能使用,必须显式删除
删除基表时,由该基表导出的所有视图定义都必须显式删除
[例8] 删除视图IS_S1。
DROP VIEW IS_S1 ;
如果有在视图IS_S1之上建立的视图IS_S2,在IS_S1被删除后IS_S2已经无法使用,这时应该使用下列语句删除IS_S1:
DROP VIEW IS_S2 ;
查询视图
查询语句:
SELECT Sno, Sage
FROM IS_Student
WHERE Sage < 20 ;
视图实体化法:通过视图定义建立视图结构下的临时表并对临时表进行查询,在查询结束后删除临时表。
视图消解法:根据视图定义将对视图的查询转换为对基本表的查询,转换后的查询语句如下:
SELECT Sno, Sage
FROM Student
WHERE Sdept = ‘IS’ AND Sage < 20 ;
信息系学生的视图定义、
CREATE VIEW IS_Student
AS SELECT Sno, Sname, Sage
FROM Student
WHERE Sdept = 'IS' ;
使用视图消解转换的查询:
错误例子:
SELECT Sno, AVG(Grade)
FROM SC
WHERE AVG(Grade)>=90
GROUP BY Sno ;
正确的查询:
SELECT Sno, AVG(Grade)
FROM SC
GROUP BY Sno
HAVING AVG(Grade)>=90 ;
正确的消解(将视图作为数据源置入FROM子句中):
SELECT *
FROM ( SELECT Sno, AVG(Grade) Gavg
FROM SC
GROUP BY Sno ) S_G
WHERE Gavg >= 90 ;
建立信息系学生的视图,并要求透过该视图进行的更新操作只涉及信息系学生。
CREATE VIEW IS_Student
AS
SELECT Sno, Sname, Sage
FROM Student
WHERE Sdept = 'IS'
WITH CHECK OPTION ;
针对此视图,当进行以下更新操作时,
修改操作:DBMS自动加上 Sdept=' IS' 的条件;
删除操作:DBMS自动加上 Sdept='IS' 的条件;
插入操作:DBMS自动检查Sdept属性值是否为'IS',
(1) 如果不是,则拒绝该插入操作
(2) 如果没有提供Sdept属性值,则自动定义Sdept为'IS'
更新视图
信息系学生视图定义:
CREATE VIEW IS_Student
AS
SELECT Sno, Sname, Sage
FROM Student
WHERE Sdept = 'IS'
WITH CHECK OPTION ;
对视图的更新语句:
UPDATE IS_Student
SET Sname = '刘辰'
WHERE Sno = '95002' ;
使用视图消解转换的更新:
UPDATE Student
SET Sname = '刘辰'
WHERE Sno= '95002' AND Sdept = 'IS';
一些视图是不可更新的,因为对这些视图的更新不能唯一地有意义地转换成对相应基本表的更新(对两类方法均如此)。
[例6] 学号及平均成绩的视图定义:
CREATE VIEW S_G (Sno, Gavg)
AS
SELECT Sno, AVG (Grade)
FROM SC
GROUP BY Sno ;
对于如下更新语句:
UPDATE S_G
SET Gavg = 90
WHERE Sno = '95001' ;
注:无论实体化法还是消解法都无法将其转换成对基本表SC的更新。
三级模式是对数据的三个抽象级别
二级映象在DBMS内部实现这三个抽象层次的联系和转换
外模式/模式映象的用途
——保证数据的逻辑独立性
模式/内模式映象的用途
——保证数据的物理独立性
视图的作用:
视图能够简化用户的操作
视图使用户能以多种角度看待同一数据
视图对重构数据库提供了一定程度的逻辑独立性
视图能够对机密数据提供安全保护
数据控制里的授权和收回权限这里没有列出,应该不重要吧。
嵌入式SQL(因为老师那个ppt写过C语言的,我就看C语言的了,其实我自己是做过java的)
什么是嵌入式SQL ( Embedded SQL )?
SQL语句嵌入到其他高级语言中,这时高级语言被称为(宿)主语言。
为什么要引入嵌入式SQL?
(1) SQL语言是非过程化语言
(2) 事务处理应用需要过程化语言
这两种方式存在差别,在程序设计的环境下,SQL语句要做某些必要的扩充。
如何区分主语言与SQL语句?
前缀:EXEC SQL
结束标志:随主语言的不同而不同
如:C语言中使用SQL:EXEC SQL <SQL语句> ;
例:EXEC SQL DROP TABLE Student ;
二、数据定义语句
[例1] 建立一个“学生”表Student。
EXEC SQL CREATE TABLE Student
( Sno CHAR(5) NOT NULL UNIQUE,
Sname CHAR(20),
Ssex CHAR(1),
Sage INT,
Sdept CHAR(15) ) ;
数据定义语句(DDL)中不允许使用主变量!
例:错误语句 EXEC SQL DROP TABLE :table_name ;
三、数据控制语句
[例2] 把查询Student表权限授给用户U1。
EXEC SQL GRANT SELECT ON TABLE Student TO U1;
四、查询结果为单记录的SELECT语句
语句格式:
EXEC SQL SELECT [ALL|DISTINCT]
<目标列表达式>[,<目标列表达式>]...
INTO <主变量>[<指示变量>]
[,<主变量>[<指示变量>]]...
FROM <表名或视图名>[,<表名或视图名>] ...
[WHERE <条件表达式>]
[GROUP BY <列名1> [HAVING <条件表达式>]]
[ORDER BY <列名2> [ASC|DESC]] ;
说明:把从数据库中找到的符合条件的记录,放到INTO子句指出的主变量中去。
[例4] 查询某个学生选修某门课程的成绩。
假设已将要查询的学生的学号赋给了主变量givensno,将课程号赋给了主变量givencno 。
EXEC SQL SELECT Sno, Cno, Grade
INTO :Hsno, :Hcno, :Hgrade:Gradeid
FROM SC
WHERE Sno=:givensno AND Cno=:givencno ;
当该学生成绩为空时,SQL语句执行后会给指示变量Gradeid置为负值,而主变量Hgrade仍保持原来的值(不正确),这时主程序应根据指示变量的值判定主变量是否为有效值。
在开发应用程序时应慎用此句:随着数据的变动或查询条件的不同,返回记录可能不止一条,造成应用程序出错。
???
六、非CURRENT形式的DELETE语句
[例8] 某个学生退学了,现要将有关他的所有选课记录删除掉。
假设该学生的姓名已赋给主变量stdname
EXEC SQL DELETE
FROM SC
WHERE Sno =
( SELECT Sno
FROM Student
WHERE Sname = :stdname ) ;
例:带有嵌入式SQL的一小段C程序:查询并打印学生成绩。
............ /* C语言的头文件、变量声明等 */
EXEC SQL INCLUDE SQLCA; /* (1) 定义SQL通信区 */
EXEC SQL BEGIN DECLARE SECTION; /* (2) 声明主变量 */
CHAR Sno(5);
CHAR Cno(3);
INT grade, Gradeid;
EXEC SQL END DECLARE SECTION;
main()
{
printf(“Input Sno and Cno:”);
scanf(“%s%s”, &Sno, &Cno);
/*(3)略去连接数据库*/
EXEC SQL SELECT Sno, Cno, Grade/* (4) 查询 */ INTO :Hsno, :Hcno, :Hgrade:Gradeid
FROM SC
WHERE Sno=:givensno AND Cno=:givencno ;
if (sqlca.sqlcode <> SUCCESS)
/* (5) 判定查询是否成功执行 */
return -1;
printf("Sno: %s, Cno: %s, Grade:%d", Sno, Cno, Grade); /*打印结果*/
/* (6) 释放连接*/
}
什么是游标(Cursor)?
游标是嵌入式SQL引入的机制
游标是SQL查询语句向宿主语言提供查询结果集的一段公共缓冲区
嵌入式SQL提供了逐条处理游标记录的功能,将当前记录各字段值推入主变量,并移动游标指针
游标解决了SQL语言只有记录处理能力的问题,将记录的各字段赋给主变量,交由宿主语言进行单值处理
使用游标的步骤
1. 说明游标
EXEC SQL DECLARE <游标名> CURSOR
FOR <SELECT语句> ;
2. 打开游标
EXEC SQL OPEN <游标名> ;
3. 移动游标指针,然后取当前记录
EXEC SQL FETCH [ [ NEXT | PRIOR | FIRST | LAST]
FROM ] <游标名>
INTO <主变量>[<指示变量>]
[,<主变量>[<指示变量>]]... ;
4. 关闭游标
EXEC SQL CLOSE <游标名> ;
一、 查询结果为多条记录的SELECT语句
[例1] 查询某个系全体学生的信息(学号、姓名、性别和年龄)。
要查询的系名由用户在程序运行过程中指定,放在主变量deptname中
......
EXEC SQL INCLUDE SQLCA; /* 包含SQL通信区*/
EXEC SQL BEGIN DECLARE SECTION;
......
/* 说明主变量 deptname, HSno, HSname, HSsex, HSage等*/
......
EXEC SQL END DECLARE SECTION;
......
gets(deptname); /* 为主变量deptname赋值 */
......
EXEC SQL DECLARE SX CURSOR FOR
SELECT Sno, Sname, Ssex, Sage
FROM Student
WHERE SDept=:deptname ; /* 定义游标 */
EXEC SQL OPEN SX /* 打开游标 */
WHILE(1) /* 用循环结构逐条处理结果集中的记录 */
{ EXEC SQL FETCH SX INTO :HSno, :HSname, :HSsex, :HSage;
/* 将游标指针向前推进一行,然后从
结果集中取当前行,送相应主变量*/
if (sqlca.sqlcode <> SUCCESS)
break;
/* 若所有查询结果已处理完或出现SQL语句错误,则退出循环 */
...... /* 由主语言语句进行进一步处理 */
} ;
EXEC SQL CLOSE SX; /* 关闭游标 */
......
游标解决了单记录SQL查询的局限性,提高了程序的健壮性。
第十章 数据库恢复技术
一、事务
事务(Transaction)是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位
事务和程序是两个概念
在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序
一个应用程序通常包含多个事务
事务是恢复和并发控制的基本单位
二、事务的定义
隐式方式:当用户没有显式地定义事务时,DBMS按缺省规定自动划分事务。
显式定义方式:
BEGIN TRANSACTION
SQL 语句1
SQL 语句2
……
COMMIT
BEGIN TRANSACTION
SQL 语句1
SQL 语句2
……
ROLLBACK
其中:
(1) COMMIT语句表示:事务正常结束,提交事务的所有操作(读+更新)事务中所有对数据库的更新永久生效
(2) ROLLBACK语句表示:事务异常终止,事务运行的过程中发生了故障,不能继续执行,回滚事务的所有更新操作,使事务滚回到开始时的状态
事务的特性:
原子性:事务中包括的诸操作要么都做,要么都不做。
一致性:比如转账,A-100,B+100,只做一个操作,数据库就处于不一致状态
隔离性:一个事务的执行不能被其他事务干扰
持久性:一个事务一旦提交,对数据的改变就是永久的
事务的这四个特性称为事务的ACID特性
第十一章 并发控制
多事务执行方式:
(1)事务串行执行
(2)交叉并发方式(interleaved concurrency)
(3)同时并发方式(simultaneous concurrency)
事务并发会带来一系列问题:
1.丢失修改
2. 不可重复读(non-repeatable read)
不可重复读是指事务1读取数据后,事务2执行更新操作,使事务1无法再现前一次读取结果。
三类不可重复读:
事务1读取某一数据后:
a)事务2对其做了修改,当事务1再次读该数据时,得到与前一次不同的值。
b)事务2删除了其中部分记录,当事务1再次读取数据时,发现某些记录神密地消失了。
c)事务2插入了一些记录,当事务1再次按相同条件读取数据时,发现多了一些记录。
后两种不可重复读有时也称为幻影现象(phantom row)。
3. 读“脏”数据(dirty read)
事务1修改某一数据,并将其写回磁盘,事务2读取同一数据后,事务1由于某种原因被撤消。这时事务1已修改过的数据恢复原值,事务2读到的数据就与数据库中的数据不一致,是不正确的数据,又称为“脏”数据。
产生上述不一致性的原因
并发操作破坏了事务的隔离性,引发了数据的不一致性。
封锁协议
排它锁(eXclusive lock,简记为X锁,又称为写锁)
若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。
共享锁(Share lock,简记为S锁,又称为读锁)
若事务T对数据对象A加上S锁,则其它事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁
两段锁协议(2PL):
事务分为两个阶段
第一阶段是获得封锁,也称为扩展阶段;
第二阶段是释放封锁,也称为收缩阶段。
例:
事务1的封锁序列:
Slock A ... Slock B ... Xlock C ... Unlock B ... Unlock A ... Unlock C;
事务2的封锁序列:
Slock A ... Unlock A ... Slock B ... Xlock C ... Unlock C ... Unlock B;
事务1遵守两段锁协议,而事务2不遵守两段协议!
2PL能解决丢失修改,不可重复读,以及读脏数据这三种情况。
活锁:由于系统调度的原因,某些事务(T2)的加锁请求得不到响应而永远等待下去,称为活锁。解决方法:采用合理的调度方法,如先来先服务(FCFS)策略。
死锁:两个或多个事务都已封锁了一些数据对象,然后又都请求对已被其他事务封锁的数据对象加锁,从而出现死等待。
预防死锁的方法:
一次封锁法:一次性将所要使用的数据全部加锁。会出现的问题有:难于事先精确确定封锁对象,降低并发度。
顺序封锁法:预先对数据对象规定一个封锁顺序。存在的问题:维护成本高和难于实现。
诊断并解除死锁:
超时法,等待图法
并发调度的可串行性
几个事务的并行执行是正确的,当且仅当其结果与按某一次序串行地执行它们时的结果相同(?)。这种并发调度策略称为可串行化(Serializable)的调度。
当多个事务的一次并发执行效果与他们的某一种串行执行效果一样时,称这种并发调度策略为可串行化的调度。
冲突可串行化调度
并发事务对同一数据的读写次序是决定事务并发状态下是否正确的唯一因素。
T1 Read(X), T2 Read(X)
T1 Read(X), T2 Write(X)
T1 Write(X), T2 Read(X)
T1 Write(X), T2 Write(X)
上述哪组指令交换次序前后不影响后续结果?
判断可串行化调度的方法有那种,就是将中间一整块儿往上移或往下移看是否等价,如果等价就是可串行化调度。
如何保证并发操作的调度是正确的
为了保证并行操作的正确性,DBMS的并行控制机制必须提供一定的手段来保证调度是可串行化的。
从理论上讲,在某一事务执行时禁止其他事务执行的调度策略一定是可串行化的调度,这也是最简单的调度策略,但这种方法实际上是不可行的,因为它使用户不能充分共享数据库资源。
保证并发操作调度正确性的方法
封锁方法:两段锁(Two-Phase Locking,简称2PL)协议
时标方法
乐观方法
结论:
并行执行的所有事务均遵守两段锁协议,则对这些事务的所有并行调度策略都是可串行化的。
即:
(1)所有遵守两段锁协议的事务,其并行执行的结果一定是正确的。
(2)事务遵守两段锁协议是可串行化调度的充分条件,而不是必要条件。
(3)可串行化的调度中,不一定所有事务都必须符合两段锁协议。
不遵循2PL,有时也能达到可串行化的目标,但这只能是一种巧合,无法保证可串行化。
两段锁协议与防止死锁的一次封锁法的比较:
一次封锁法要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行,因此一次封锁法遵守两段锁协议;
但是两段锁协议并不要求事务必须一次将所有要使用的数据全部加锁,因此遵守两段锁协议的事务可能发生死锁。
例:遵守两段锁协议的事务发生死锁
封锁粒度略去
第十一章总结
总结
事务是对数据库操作(查询、更新)的最小逻辑单位,一个应用程序包含一个或多个事务程序;
允许多个应用程序的并发执行是提高数据库系统性能的要求,但多处事务程序对同一数据的并发操作可能带来数据的不一致性;
解决不一致性的方法是对数据加锁,封锁协议是对数据封锁规则的描述,2PL协议可以避免某些并发过程中造成的数据不一致性;
死锁是两个(及以上)事务对同一组数据先后加锁而引起的相互等待而僵迟,使每一事务程序都无法执行下去;
一个并发调度,通过交换冲突可交换语句,能够转换为一个串行调度,则该并发调度称为可串行化调度;
符合2PL协议的事务可以保证数据的一致性和可串行化调度,但不能避免死锁;
加锁的粒度是对加锁数据对象大小的描述,可以是数据库、表和记录,封锁粒度的大小直接影响系统的性能;
隔离级别是DBMS提供的并发控制设置,应面向不同的需求选择合理的隔离级别;DBMS根据隔离级别的设置,在安排事务执行时,适当地加入必须的锁指令,以控制事务的调度;
第五章 关系数据库理论
函数依赖
x决定y,y不包含于X,x决定y是非平凡的函数依赖
x决定y,y包含于x,x是平凡的函数依赖
x->z,(x,y)->z是部分函数依赖
(x,y)->z是完全函数依赖
有多个候选码时,选定一个作为主码
候选码的判定是:
只出现在左边的一定是候选码
只出现在右边的一定不是候选码
左右都出现的不确定
不确定的判定方法是,拿出一个找他X的闭包,如果闭包全部都有,就是候选码
要找所有候选码的话,如果闭包不是全集,可以XA加一个再接着往后找
例:设R<U, F>,其中: U={A,B,C,D,E},F={A→BC, CD→E, B→D, E→A},求R的所有候选码。
(5) BCD包含已求得的候选码BC,BCD不是码,结束。
故关系R的候选码为:A,E,BC,CD。
注意:如果存在这种(x,y)->z u->y
这样的y是算左右两边都出现的
主属性:所有候选码中出现的属性
非主属性:不出现在任何候选码中的属性
函数依赖的公理系统
1.自反律:U包含X,X包含Y,则X->Y
2.增广律:X ->Y,U包含Z,则XZ->YZ
3.传递率:X->Y,Y->Z,则X->Z
三条推理规则
合并规则:X->Y,Y->Z,则X->YZ
分解规则:X->Y,Y包含Z,则X->Z
伪传递规则:X->Y,WY->Z,则WX->Z
函数依赖集的闭包
属性集的闭包
这两应该可以直接手算
Armstrong公理系统是有效的、完备的。
有效性是指由F出发根据Armstrong公理推导的每一FD都在F+中;
完备性是指F+中的每一FD都可以F出发根据Armstrong公理推导推导出来。
最小函数依赖集
定义:如果函数依赖集F满足下列条件,则称F为一个极小函数依赖集。亦称为最小依赖集或最小覆盖。
(1) F中任一函数依赖的右部仅含有一个属性;
(2) F中不存在这样的函数依赖X→A,使得F与F-{X→A}等价;
(3) F中不存在这样的函数依赖X→A,X有真子集Z使得 (F-{X→A} )∪{Z→A}与F等价。
最小函数依赖集求解算法:
(1) 对F中每一函数依赖X→Y ,若Y= A1A2…Am(m≥2),则用{ X→Ai | i=1,…,m }替换X→Y ;(等价变换)
(2) 对F中每一函数依赖X→A,若X= B1B2…Bn,逐一考察Bi,若A(X-Bi)F+,则用(X-Bi)→A替换X→A,Bi 称为无关属性;(等价变换)
(3) 对于F中的每一函数依赖X→A,若A XF-{X→A}+,则从F中去掉X→A。 (等价变换)
定理:每一函数依赖集F均与其对应的最小函数依赖集Fmin等价。(证明:在构造Fmin的过程中每一步变换都是等价的)
例:设关系模式R(ABCDE) 上的函数依赖集F={A→BC, BCD→E, B→D, A→D, E→A},求F的最小函数依赖集。
解:① 对每个函数依赖右部属性分离,得:
F1={A→B, A→C, BCD→E, B→D, A→D, E→A}
② 去掉左部冗余属性
∵ (BC)F+=BCDEA,包含E,BCD→E中的D为冗余属 性,以BC→E取代BCD→E,得:
F2={A→B, A→C, BC→E, B→D, A→D, E→A}
③ 去掉多余函数依赖
∵ A→B, B→D可以得到A→D,故A→D多余,去掉,得Fmin={A→B, A→C, BC→E, B→D, E→A}
最小函数依赖就是,先把右边的属性分离,再对左边BCD这种,看是否能化简,最后去掉多余的函数依赖如A->B,B->C,A->C去掉A->C
结论:一个给定的函数依赖集F的最小函数依赖集不是唯一的。
原因:在求解过程中由于考察FD的次序的不同会产生不同的结果,但一个函数依赖集F的所有最小函数依赖集是等价的(都等价于F)。
函数依赖集F的正则覆盖
Fc中任何函数依赖的左右部分都不含无关属性
Fc中任何函数依赖的左部都是唯一的
正则覆盖算法:
求出最小函数依赖集
对最小函数依赖集中左部属性相同的函数依赖使用合并规则进行合并
Fmin = {A→B, A→C, BC→E, B→D, E→A}
Fc = {A→BC, BC→E, B→D, E→A}
范式
1NF:列不可再分,关系数据库就是一范式,所以不用判断。
2NF:非主属性完全依赖
3NF:非主属性没有传递依赖
BCNF:左边都是码
4NF:多值依赖只有两个,
不属于2NF出现的问题:(1) 插入异常 (2) 删除异常(3) 数据冗余度大 (4) 修改异常
不属于3NF出现的问题:(1) 插入异常 (2) 删除异常(3) 数据冗余度大 (4) 修改异常
不属于BCNF出现的问题:(1) 插入异常 (2) 删除异常(3) 数据冗余度大 (4) 修改异常
BCNF消除了主属性对码的部分依赖和传递依赖,在函数依赖的范畴内解决了数据插入异常和删除异常,但可能存在着数据冗余和修改复杂。
多值依赖
X->->Z,
比如
X | Y | Z |
x | y1 | z1 |
x | y2 | z1 |
x | y1 | z2 |
x | y2 | z2 |
特殊的多值依赖
X->->Y时,若Z=空,称为平凡的多值依赖
,Z不为空时,就是非平凡的多值依赖
对1NF而言如果有非平凡的多值依赖,则为4NF
模式分解
模式分解应该分解到BCNF或者4NF
分解
(怎么CSDN的博客草稿箱这么多问题,我明明都保存了,后面的模式分解的内容都没了)