标签:
为了维护数据库完整性DBMS需要提供:
1. 提供定义完整性约束条件的机制
2. 提供完整性检查方法:一般在INSERT UPDATE DELETE语句执行后开始检查或者在事物提交之前进行检查
3. 违约处理机制:比如拒绝,级联或者其他操作
用PRIMARY KEY进行定义,对于单属性,实体完整性可以定义为列级约束也可以定义为表级约束;对于多个属性构成的码,只能定义为表级约束。
例如:
定义为列级约束(列级主码)
CREATE TABLE S(
Sno CHAR(9) PRIMARY KEY,
Sname CHAR(20) NOT NULL,
.....
);
定义为表级约束(表级主码)
CREATE TABLE S(
Sno CHAR(9) ,
Sname CHAR(20) NOT NULL,
.....
PRIMARY KEY(Sno)
);
检查和违约处理:
1. 检查主码值是否唯一,如果不唯一就拒绝插入或者修改(全表扫描或者在DBMS为主码建立的索引上进行查找,例如B+树索引)
2. 检查主码值对应的各个属性是否为空,如果存在为空的属性,那么拒绝插入或者修改
在创建表的时候使用FOREIGN KEY 定义外码,用REFERENCES短语指定这些外码参照哪些表的主码。和主码类似,外码也同样可以定义表级和列级参照完整性。不过感觉没什么区别
例如:
CREATE TABLE SC(
Sno CHAR(9) NOT NULL,
Cno CHAR(4) NOT NULL,
.....
PRIMARY KEY(Sno, Cno),
FOREIGN KEY (Sno) REFERENCES Sudent(Sno),
FOREIGN KEY (Cno) REFERENCES Course(Cno),
);
破坏参照完整性的情形以及违约处理:
1. SC表中插入一个元组但是该元组的Sno属性在被参照表Student中是不存在的
2. SC表中更新一个元组但是该元组的Sno属性在被参照表Student中是不存在的
3. Student表中删除一个元组,导致参照表SC中某些元组的Sno在Student表中不存在
4. Student表中更新一个元组,导致参照表SC中某些元组的Sno在Student表中不存在
发生不一致的时候一般采取的措施是:
1. 拒绝执行
2. 级联操作:删除或者修改被参照表导致不满足参照完整性的时候,级联删除惨遭表中所有的不一致元组
3. 设置空值(这也引起一个问题就是在定义外码的时候是否允许外码列为空,如果不允许为空,那么就不能按3来处理)
至于采用哪种处理策略,可以在建表的时候显式指定
CREATE TABLE SC(
Sno CHAR(9) NOT NULL,
Cno CHAR(4) NOT NULL,
.....
PRIMARY KEY(Sno, Cno),
FOREIGN KEY (Sno) REFERENCES Sudent(Sno)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (Cno) REFERENCES Course(Cno)
ON DELETE NO ACTION
ON UPDATE CASCADE,
);
根据具体应用而定义的数据必须满足的语义要求。分类:
CREATE TABLE SC(
Sno CHAR(9) UNIQUE,
Cno CHAR(4) NOT NULL,
Grade SMALLINT CHECK(Grade >=0 AND Grade <=100),
.....
PRIMARY KEY(Sno, Cno),
FOREIGN KEY (Sno) REFERENCES Sudent(Sno),
FOREIGN KEY (Cno) REFERENCES Course(Cno),
);
和前面一样,用户自定义完整性同样是可以定义为列级限制也可以定义为表级限制。入上述例子就是列级用户自定义完整性,表级用户自定义完整新如下:
CREATE TABLE Student(
Sno CHAR(9) UNIQUE,
Sname CHAR(8) NOT NULL,
Ssex CHAR(2),
.....
PRIMARY KEY(Sno),
CHECK (Ssex = ‘女‘ OR Sname NOT LIKE ‘Ms.%‘)
);
两者的区别是表级限制可以定义不同属性取值之间的限制。如上述的例子中定义了性别属性以及姓名属性两者之间的约束。
约束检查和违约处理:
一般采用拒绝执行的方式处理。
除了直接使用上述的3中完整性约束之外,SQL还提供了CONSTRAINT完整性约束命名子句,用来对完整性约束条件命名,以方便增加和删除完整性约束。
完整性命名子句的定义:
直接看例子:
CREATE TABLE Student(
Sno NUMERIC(6)
CONSTRAINT C1 CHECK(Sno BETWEEN 90000 AND 99999),
Sname CHAR(8)
CONSTRAINT C2 NOT NULL,
Sage NUMERIC(3)
CONSTRAINT C3 CHECK(Sage < 30),
Ssex CHAR(2)
CONSTRAINT C4 CHECK(Ssex IN (‘男‘, ‘女‘)),
.....
CONSTRAINT StudentKey PRIMARY KEY(Sno)
);
完整性命名子句的修改:
直接删除并重新定义即可
ALTER TABLE Student
DROP CONSTRAINT C1;
ALTER TABLE Student
ADD CONSTRAINT C1 CHECK(Sno BETWEEN 900000 AND 9999999);
触发器是用户定义在关系表上的一类由事件驱动的特殊过程。定义之后,任何用户对数据库的增删该操作均由DBMS自动激活相应的触发器。触发器类似于约束但是比约束更加灵活。可以实现比foreign key check约束更为复杂的检查和操作,具有更加精细和强大的数据控制能力。
触发器实例:
CREATE TABLE Sql_log(
Eno NUMERIC(4) REFERENCE teacher(Eno),
Sal NUMERIC(7, 2),
Username CHAR(10),
Date TIMESTAMP
);
CREATE TRIGGER Insert_Sal
AFTER INSERT ON Teacher
FOR EACH ROW
AS BEGIN
INSERT INTO Sal_log VALUES(new.Eno, new.Sal, CURRENT_USER, CURRENT_TIMESTAMP);
END;
CREATE TRIGGER Update_Sal
AFTER UPDATE ON Teacher
FOR EACH ROW
AS BEGIN
IF(new.Sal <> old.Sal) THEN INSERT INTO Sal_log VALUES(new.Eno, new.Sal, CURRENT_USER, CURRENT_TIMESTAMP);
END IF;
END;
注意:
1. 表的拥有者才可以创建该表的触发器
2. 触发事件可以使INSERT / DELETE /UPDATE也可以是三者的组合
3. 行级触发器
同一个表上的触发器激活顺序:
1. 执行before触发器-同一个表上的多个before触发器按定义顺序执行
2. 激活触发器的sql语句
3. 触发器被激活之后,只有当触发条件为真的时候才执行触发动作体。如果省略when触发条件,那么触发动作体在触发器被激活之后立刻执行
4. 触发动作体既可以是一个匿名SQL语句也可以是对已经创建的存储过程的调用。
触发器的删除:
被删除的触发器必须是一个已经创建的触发器,而且删除者也必须有相应的用户权限。
DROP TRIGGER Insert_Sql ON Teacher;
触发器分为事前触发和事后触发,两者的区别?行级触发(FOR EACH ROW)和语句级触发( FOR EACH STATEMENT)的区别是什么?
事前触发发生在事件发生之前,用验证一些条件或者准备工作;事后触发发生在事件发生之后,做收尾工作。事前触发可以获取之前的值old和新值new,事后触发可以保证事务的完整性。
语句级触发可以在语句执行之前或者执行之后进行,一般只执行一次,而行级触发,触事件根据被影响的行的数量,一般会执行多次。同时,行级触发器可以使用new 和old来引用update/insert事件执行前后的值,但是语句级触发是不行的。
范式就是符合一定的级别的关系模式的集合,一般有1NF 2NF 3NF BCNF 4NF
1NF是指满足数据库中的每一列都是不可再分的基本数据项,是数据库最基本的要求(同一列中不能有多个值或者出现重复属性)。
2NF是在1NF的基础上,消除了每一个非主属性的部分函数依赖。通俗的讲就是要求数据库中的每一行或者每一个实例是可以唯一的被区分开(不存在多种区分方式,也就没有了部分函数依赖)。
3NF 是在2NF的基础上消除了非主属性的传递函数依赖。
BCNF在3NF的基础上又消除了主属性对码的传递依赖和部分依赖,也就是说BCNF消除了任何属性(包括主属性和非主属性)对码的部分依赖和传递依赖。
一个特殊的BCNF例子就是全码,显然全码不存在非主属性,因此至少是3NF,而且全码也不存在传递和部分依赖,所以也是BCNF
BCNF是函数依赖范围内的最佳优化,基本消除了插入和删除异常,但是对多值依赖范围内是无效的。
4NF限制关系模式的属性之间不存在非平凡且非函数依赖的多值依赖(唯一允许的非平凡多值依赖是函数依赖)。
涉及到的概念:多值依赖,平凡多值依赖,函数依赖等等,直接找本书看看就可以了,确实抽象了一点点。
在多值依赖范围内,4NF已经是优化程度最高的。
规范化过程:
1NF消除非主属性的部分函数依赖->2NF消除非主属性的函数依赖->3NF消除主属性的部分函数依赖和传递函数依赖->BCNF消除非平凡且非函数依赖的多值依赖->4NF
视图是从一个或者多个基本表中导出的表,数据库中值存放视图的定义而不存放对应视图的数据。视图被定义之后就可以和基本表一样被查询和删除,同时在视图之上还可以继续定义视图。对视图的更新操作(增删改)是有一定的限制
视图的定义:
CREATE VIEW IS_Student
AS
SELECT Sno, Sname, Sage
FROM Student
WHERE Sdept=‘IS‘
WITH CHECK OPTION;
WITH CHECK OPTION表示对数据进行更新update insert delete操作的时候需要保证更新操作满足定义视图中的谓词条件。也就是AS之后的子查询。
此外,组成视图的属性列名要么全部省略要么全部指定,必须指定列名的情形:1)目标列是聚集函数或者是列表达式 2)多表连接时选择了同名列作为视图的字段 3)需要在视图中定义更合适的名字。
如上述的实例,所创建的视图仅仅是从一个基本表中导出,去掉了基本表的某些行某些列但是保留了主码,此类视图称为是行列子集视图。
CREATE VIEW BT_S(Sno, Sname, Sbirth)
AS
SELECT Sno, Sname, 2016-Sage
FROM Student
在视图中的数据是不存储的,有些时候,视图中的列是经过基本表派生出来的,这些派生列由于在数据库中并不存储,因此被称为是虚拟列。带虚拟列的视图也被称为是带表达式的视图;
CREATE VIEW S_G(Sno, Gavg)
AS
SELECT Sno, AVG(Grade)
FROM SC
GROUP BY Sno;
使用聚集函数和GROUP BY子句的查询来定义的视图被称为是分组视图。
行列子集视图是可以更新的,但是分组视图和带表达式的视图一般是不可更新的。
视图的删除,一般删除和级联删除。级联删除的时候,基于本视图而定义的视图也被删除。
视图消解:在进行基于视图的查询的时候,首先会进行有效性检查,通过之后,把定义的子查询和用于的查询结合起来,转化为等价的基本表的查询,最后执行修正了的查询。该转换过程就称为是视图消解。
视图消解并不一定总是成功的,尤其是非行列子集视图,因此这类视图的查询尽量直接基于基本表进行。
对视图的更新也是基于视图消解进行的,而且视图的更新要求更加严格,除了行列子集视图是可以直接更新之外,其他视图有些视图理论上就被证明是无法更新的。
视图的作用:
1. 简化用户操作
2. 使用户能够以多种角度看待同一数据
3. 视图对于重构数据库提供了一定程度的逻辑独立性
4. 视图可以对机密数据提供安全保护
5. 适当的视图可以实现更加清晰简洁的查询
事务是指用户定义的一个数据库操作序列,这些操作序列是一个不可分割的工作单位,要么全做要么全不做。事务的开始和结束可以由用户进行显示的定义和控制,如果没有定义事务,那么由DBMS按缺省规定自动划分事务。
事务的特性:
1. 原子性
2. 一致性:事务的执行时使数据库从一个一致性状态到达另外一个一致性状态
3. 隔离性:一个事务内部的操作及使用的数据对于其他并发执行的事务而言是隔离的,也就是并发执行的各个事务之间是互不干扰的。
4. 持续性:一个事务一旦提交,对于数九的更改就是永久的。接下来的事务或者故障不应对其产生影响
事务是恢复和并发控制的基本单位
可能破坏ACID特性的场景:
1. 多个事务并发执行,不同的事务出现交叉
2. 事务在运行过程中被强行停止
一个查询中涉及多个表,该查询称为是连接查询。包括等值连接查询,自然连接查询,非等值连接查询,自身连接查询,外连接查询和符合条件连接查询。
当连接运算符为’=’的时候,称为是等值连接,其他都是非等值连接。在等值连接中,将目标列中的重复的去掉,称为是自然连接。
查询中的连接如果是一个表与自身进行连接,称为是自身连接。
通常的查询中,只有满足连接条件的元组才会输出,如果在插叙中将主体表中不满足条件的元组一并输出,并且在不满足条件的列上填NULL,这种类型的连接称为是外连接。根据主体表的选择的不同,尅分为左外连接(主体表为左边关系,输出左边关系中不满足连接条件的列)和右外连接(主体表为右边关系,输出右边关系中不满足连接条件的列)。
如果where子句中,有多个条件(连接条件或者其他限定条件),称为复合条件连接。
例如:
SELECT Student.Sno, Sname
FROM Student, SC
WHERE Student.Sno=SC.Sno AND SC.Cno=‘2‘ AND SC.Grade>90;
连接可以使两个表之间,也可以是多个表之间,多表之间的连接称为是多表连接。
SQL的执行需要先进行编译然后才可以执行。大型DBMS为了提高效率,将完成特定功能的SQL语句进行编译优化,存储在数据库服务器中,用户可以通过指定存储过程的名字来调用执行。
创建:
create procedure pro_name @ [参数名] [类型]
as
begin
….
end
调用: exec pro_name [参数名]
删除: drop procedure pro_name
存储过程可以增强SQL语言的功能和灵活性,因为可以使用流程控制语句编写,所以具有很强的灵活性,可以用于实现复杂的判断和运算。存储过程不是函数,两者的区别:
1. 存储过程可以作为独立的部分执行,而函数可以作为查询语句的一部分被调用
2. 存储过程一般实现的功能比较复杂,而函数实现的比较有针对性
3. 函数可以嵌套在SQL中,也可以在select中使用,而存储过程不可以
4. 函数不可以操作实体表,只能操作内建表
5. 存储过程创建的时候就在服务器上进行了编译,所以速度比较快
标签:
原文地址:http://blog.csdn.net/sugar_z_/article/details/51437745