第一章 概论
一、基本概念
- 数据(Data) 是数据库中存储的基本对象,描述事物的符号记录。例如学生的学号、姓名等信息都是数据。
- 数据库(Database,DB) 长期存储在计算机内、有组织的、可共享的大量数据的集合。像学校的教务管理系统中的学生信息库。
- 数据库管理系统(Database Management System,DBMS) 位于用户与操作系统之间的一层数据管理软件。它的主要功能包括数据定义、数据操纵、数据库的运行管理、数据库的建立和维护等。例如 MySQL、Oracle 等都是 DBMS。
- 数据库系统(Database System,DBS) 由数据库、数据库管理系统(及其应用开发工具)、数据库管理员(DBA)和用户构成。
二、数据模型分类及三要素
1.数据模型分类
概念模型 :按用户的观点对数据和信息建模,主要用于数据库设计。例如 E - R 模型(实体 - 关系模型)。
逻辑模型 :按计算机系统的观点对数据建模,包括层次模型、网状模型、关系模型等。关系模型是目前最常用的逻辑模型,如在 MySQL 中使用关系模型来组织数据。
物理模型 :描述数据在存储介质上的组织结构,与具体的 DBMS 和硬件有关。
2.数据三大模型
层次模型: 像一棵树一样,有根节点、父节点和子节点,节点之间是一对多的联系。例如一个公司的部门组织架构可以用层次模型表示,公司总部是根节点,下设各个部门是子节点。树状结构
网状模型: 节点之间可以是多对多的联系,其结构像网一样。例如交通网络中,各个城市(节点)之间有多条道路(联系)相连。网状结构
关系模型: 以二维表的形式来组织数据,表中的一行称为一个元组,一列称为一个属性。例如学生表(学号,姓名,年龄,专业)就是一个关系模型。二维表
3.数据模型的三要素
数据结构 :描述数据库的组成对象以及对象之间的联系。例如关系模型中的关系(二维表)结构。
数据操作 :对数据库中各种对象(型)的实例(值)允许执行的操作的集合,包括查询和更新(插入、删除、修改)等操作。
数据的完整性约束条件 :一组完整性规则的集合。例如在关系模型中,实体完整性要求关系的主键不能为空值。
三、三级模式与二级映像
- 三级模式
外模式(External Schema) :是数据库用户(包括应用程序员和最终用户)能够看见和使用的局部数据的逻辑结构和特征的描述,是数据库用户的数据视图,是与某一应用有关的数据的逻辑表示。是用户与数据库系统的接口,是用户用到的那部分数据的描 述。例如,在学校的教务管理系统中,教师查询学生成绩的界面所涉及的数据结构就是一种外模式。局部逻辑
模式(Schema) :也称逻辑模式,是数据库中全体数据的逻辑结构和特征的描述,是所有用户的公共数据视图。它是数据库系统模式结构的中间层,既不涉及数据的物理存储细节和硬件环境,也与具体的应用程序、开发工具及高级程序设计语言无关。全局逻辑
内模式(Internal Schema) :也称存储模式,是数据物理结构和存储方式的描述,是数据在数据库内部的表示方式。例如数据在磁盘上的存储方式,如顺序存储、hash法,是否加密和压缩等。物理结构
- 二级映像
外模式 / 模式映像 :定义了外模式与模式之间的对应关系。当模式改变时(例如增加新的关系、改变关系的属性等),由数据库管理员对各个外模式 / 模式的映像做相应改变,可以使外模式保持不变。应用程序是依据外模式编写的,从而应用程序不必修改,保证了数据的逻辑独立性。
模式 / 内模式映像 :定义了模式与内模式之间的对应关系。当数据库的内模式(例如存储结构、存储方式等)发生改变时,由数据库管理员对模式 / 内模式映像做相应改变,可以使模式保持不变,从而应用程序也不必改变,保证了数据的物理独立性。
第二章 关系数据库
一、关系代数计算
- 选择(σ) 从关系中选择满足给定条件的元组。例如,有学生关系表 Student(学号,姓名,年龄,性别),要选择年龄大于 20 岁的学生,关系代数表达式为:σ 年龄 > 20 (Student)。
- 投影(π) 从关系中选择若干属性列组成新的关系。例如,从学生关系表 Student 中只选择学号和姓名这两个属性,关系代数表达式为:π 学号,姓名 (Student)。
- 自然连接(⨝) 是一种特殊的等值连接,它要求两个关系中进行比较的分量必须是相同的属性组,并且在结果中把重复的属性列去掉。例如有学生关系表 Student(学号,姓名,专业)和选课关系表 CourseSelection(学号,课程号,成绩),要得到学生的学号、姓名、课程号和成绩的关系,关系代数表达式为:Student ⨝ CourseSelection。
- 除(÷) 设关系 R (X,Y) 和 S (Y),其中 X、Y 可以是单个属性或属性集。R÷S 的结果是一个关系,其属性为 X,元组是满足以下条件的 X 值:在 R 中与该 X 值对应的 Y 值的集合包含 S 中的所有 Y 值。例如,有供应商关系表 Supplier(供应商编号,供应零件编号)和零件关系表 Part(零件编号),要找出能供应所有零件的供应商编号,就可能用到除运算。
- 并(∪)、交(∩)、差( - )、笛卡尔积(×)
- 并 :设关系 R 和 S 具有相同的关系模式,R∪S 是由属于 R 或属于 S 的元组组成的集合。例如有两个关系 R(1,2)和 S(2,3),R∪S ={(1,2),(2,3)}。
- 交 :设关系 R 和 S 具有相同的关系模式,R∩S 是由既属于 R 又属于 S 的元组组成的集合。例如 R(1,2)和 S(2,3),R∩S ={(2,3)}。
- 差 :设关系 R 和 S 具有相同的关系模式,R - S 是由属于 R 但不属于 S 的元组组成的集合。例如 R(1,2)和 S(2,3),R - S ={(1,2)}。
- 笛卡尔积 :设关系 R 为 m 元关系,有 k1 个元组;关系 S 为 n 元关系,有 k2 个元组。则 R×S 是一个 m + n 元关系,有 k1×k2 个元组。例如 R(a,b),S(c,d),R×S=(a,b,c,d)。
比较运算符:如大于(>)、小于(<)、等于(=)等,用于条件判断。
逻辑运算符:与(∧)、或(∨)、非(¬),用于组合多个条件。
二、根据查询要求写出关系代数表达式
- 仔细分析查询需求,确定需要使用的关系代数运算。
- 按照运算顺序准确写出表达式。例如,要查询选修了课程号为 'C1' 且成绩大于 80 分的学生的学号和姓名,假设学生关系为 Student(学号,姓名),选课关系为 CourseSelection(学号,课程号,成绩),关系代数表达式为:π 学号,姓名 (σ 课程号 = 'C1'∧成绩> 80 (Student ⨝ CourseSelection))。
第三章 SQL 语言
一、SQL 语言的基本功能
-
数据定义(DDL) 用于定义数据库、表、视图、索引等数据库对象。
CREATE:用于创建数据库、表、索引等数据库对象。例如创建一个学生表:CREATE TABLE student (student_id INT PRIMARY KEY, name VARCHAR(50), age INT);
ALTER:修改数据库对象的结构。如给学生表增加一个性别列:ALTER TABLE student ADD COLUMN gender VARCHAR(10);
DROP:删除数据库对象。如删除一个表:DROP TABLE student;
-
数据操纵(DML) 包括对数据库中数据的插入(INSERT)、更新(UPDATE)、删除(DELETE)操作
INSERT:向表中插入数据。例如向学生表插入一条记录:INSERT INTO student (student_id, name, age) VALUES (1, 'John', 20);
UPDATE:更新表中的数据。如将学号为1的学生年龄改为21:UPDATE student SET age = 21 WHERE student_id = 1;
DELETE:从表中删除数据。如删除学号为1的学生记录:DELETE FROM student WHERE student_id = 1;
-
**数据查询(DQL)**是 SQL 语言的核心功能,用于从数据库中查询数据。
SELECT:是SQL中最常用的语句,用于从一个或多个表中查询数据。例如查询所有学生的姓名和年龄:SELECT name, age FROM student;
-
**数据控制(DCL)**用于控制用户对数据库的访问权限,包括授权(GRANT)和收回权限(REVOKE)等操作。
GRANT:授予用户权限。如授予用户user1对学生表的查询权限:GRANT SELECT ON student TO user1;
REVOKE:收回用户权限。如收回用户user1对学生表的查询权限:REVOKE SELECT ON student FROM user1;
二、定义数据库、定义表的 SQL 命令
- 定义数据库 基本语法:CREATE DATABASE database_name; 其中 database_name 是要创建的数据库名称。例如 CREATE DATABASE school;
- 定义表 基本语法:CREATE TABLE table_name (column1 datatype [constraint],column2 datatype [constraint],...); 例如 CREATE TABLE course (课程号 VARCHAR (10) PRIMARY KEY, 课程名 VARCHAR (50), 学分 INT); 这里的 PRIMARY KEY 是约束条件,表示课程号是主键。还可以定义外键约束,如 CREATE TABLE CourseSelection (学号 VARCHAR (10), 课程号 VARCHAR (10), 成绩 INT,FOREIGN KEY (学号) REFERENCES student (学号),FOREIGN KEY (课程号) REFERENCES course (课程号));
三、基本查询、条件查询、分组、排序、聚集函数、top 子句
- 基本查询 : 使用 SELECT 语句查询表中的所有数据,如 SELECT * FROM table_name。
- 条件查询 : 在 SELECT 语句中使用 WHERE 子句来指定查询条件。例如,查询年龄大于 20 岁的学生:SELECT * FROM student WHERE 年龄 > 20。对于空值的判断,可以使用 IS NULL 或 IS NOT NULL。例如,查询没有成绩的选课记录:SELECT * FROM CourseSelection WHERE 成绩 IS NULL。
- 分组(GROUP BY) : 按照指定的列对查询结果进行分组。例如,查询每个专业的学生人数:SELECT COUNT (*), 专业 FROM student GROUP BY 专业。
- 排序(ORDER BY) : 使用 ORDER BY 子句对查询结果进行升序(ASC,默认)或降序(DESC)排序。例如,查询学生信息并按照年龄从小到大排序:SELECT * FROM student ORDER BY 年龄 ASC。
- 聚集函数 : 如 COUNT 计算行数、SUM 计算总和、AVG 计算平均值、MAX 计算最大值、MIN 计算最小值等。例如,计算学生的平均年龄:SELECT AVG (年龄) FROM student。
- top 子句 : 在不同的 DBMS 中有不同的实现方式,用于限制查询结果的行数。例如在 SQL Server 中:SELECT TOP 10 * FROM student; 在 MySQL 中:SELECT * FROM student LIMIT 10。
四、嵌套查询、连接查询
- 嵌套查询 是指将一个查询块嵌套在另一个查询块的 WHERE 子句或 HAVING 子句中的查询。例如,查询选修了课程名为 ' 数学 ' 的学生学号,假设课程表为 course(课程号,课程名),选课表为 CourseSelection(学号,课程号),可以先查询出 ' 数学 ' 课程的课程号,再查询选修该课程号的学生学号。内层查询:SELECT 课程号 FROM course WHERE 课程名 = ' 数学 '; 外层查询:SELECT 学号 FROM CourseSelection WHERE 课程号 =(SELECT 课程号 FROM course WHERE 课程名 = ' 数学 ');
- 连接查询 用于将多个表中的数据按照一定的条件组合在一起。例如内连接(INNER JOIN):SELECT student. 学号,student. 姓名,course. 课程名,CourseSelection. 成绩 FROM student INNER JOIN CourseSelection ON student. 学号 = CourseSelection. 学号 INNER JOIN course ON CourseSelection. 课程号 = course. 课程号;还可以有左连接(LEFT JOIN)、右连接(RIGHT JOIN)、全连接(FULL JOIN)等不同类型的连接查询。
五、插入新记录、更新数据、删除数据
- 插入新记录 使用 INSERT INTO 语句。例如,INSERT INTO student (学号,姓名,年龄) VALUES ('001',' 张三 ',20); 如果要插入所有列的值,可以省略列名,如 INSERT INTO student VALUES ('001',' 张三 ',20);
- 更新数据 使用 UPDATE 语句。例如,UPDATE student SET 年龄 = 21 WHERE 学号 ='001';
- 删除数据 使用 DELETE FROM 语句。例如,DELETE FROM student WHERE 学号 ='001';
六、索引的建立语句、分类、作用
- 建立语句 基本语法:CREATE [UNIQUE] INDEX index_name ON table_name (column1 [ASC|DESC],column2 [ASC|DESC],...); 其中 UNIQUE 表示创建唯一索引,index_name 是索引名称,table_name 是要创建索引的表名,column1、column2 等是要创建索引的列名,可以指定升序(ASC)或降序(DESC)排列。例如,CREATE INDEX idx_name ON student (姓名);
- 分类
- 聚集索引(clustered) :该索引中键值的逻辑顺序决定了表中相应行的物理顺序。一个表只能有一个聚集索引。
- 非聚集索引(non - clustered) :索引的逻辑顺序与表中行的物理顺序不同。一个表可以有多个非聚集索引。
- 作用 提高查询速度,通过快速定位数据的物理位置或逻辑位置,减少查询时的磁盘 I/O 操作。
七、视图的建立 SQL 命令
- 基本语法:CREATE VIEW view_name AS SELECT column1,column2,... FROM table_name WHERE condition; 例如,CREATE VIEW young_student AS SELECT * FROM student WHERE 年龄 < 20; 视图是一个虚拟表,它是从一个或多个基本表(或视图)导出的表,视图本身不存储数据,数据仍然存储在基本表中。
第四章 数据库安全性
一、安全性基本定义
数据库安全性是指保护数据库以防止不合法的使用所造成的数据泄露、更改或破坏。例如,防止非法用户登录数据库系统查看或修改敏感数据,如学生的成绩信息、用户的银行账户信息等。
二、自主存取控制
- 授权(GRANT) 用于将对数据库对象(如表、视图等)的操作权限授予用户或角色。例如,授予用户 user1 对学生表 student 的查询权限:GRANT SELECT ON student TO user1; 还可以授予多个权限,如 GRANT SELECT,INSERT ON student TO user1;
- 收回权限(REVOKE) 与授权操作相反,用于收回用户或角色对数据库对象的操作权限。例如,收回用户 user1 对学生表 student 的查询权限:REVOKE SELECT ON student FROM user1; 在授权和收回权限的语句中,直接在 ON 后面跟表名或视图名,不需要写 table 或者 view 字样。
第五章 数据库完整性
一、基本概念
数据库完整性是指数据的正确性和相容性。正确性是指数据是符合现实世界语义、反映当前实际状况的;相容性是指数据库同一对象在不同关系表中的数据是符合逻辑的。例如,在学生关系表中,学号是唯一标识一个学生的,不能有两个学生具有相同的学号,这就是一种完整性约束。
二、完整性约束类型
- 实体完整性 要求关系中的主键属性不能为空值且不能有重复值。例如在学生关系表 Student(学号,姓名,年龄)中,学号为主键,那么学号列不能有 NULL 值,并且每个学号值必须是唯一的。
- 参照完整性 是关系之间的一种约束,用于维护相关关系之间数据的一致性。例如有学生关系表 Student(学号,姓名,专业编号)和专业关系表 Major(专业编号,专业名称),在 Student 表中的专业编号必须参照 Major 表中的专业编号,即 Student 表中的专业编号要么为空(如果允许的话),要么必须是 Major 表中存在的专业编号。
- 用户定义完整性 是针对某一具体应用的完整性约束条件,反映某一具体应用所涉及的数据必须满足的语义要求。例如,在学生关系表中,年龄的取值范围可能被定义为 15 - 40 岁,这就是用户定义的完整性约束。
三、实现完整性约束的方式
在定义表时通过约束条件来实现。例如,在创建学生表时定义主键约束:CREATE TABLE student (学号 VARCHAR (10) PRIMARY KEY, 姓名 VARCHAR (20), 年龄 INT); 定义外键约束:CREATE TABLE student (学号 VARCHAR (10), 姓名 VARCHAR (20), 专业编号 VARCHAR (10),FOREIGN KEY (专业编号) REFERENCES major (专业编号)); 定义用户定义完整性约束可以通过 CHECK 约束(在不同的 DBMS 中有不同的支持情况),如 CREATE TABLE student (学号 VARCHAR (10), 姓名 VARCHAR (20), 年龄 INT CHECK (年龄 BETWEEN 15 AND 40));
四、综合应用
在数据库设计和操作过程中,要综合考虑各种完整性约束。例如,在进行数据插入、更新、删除操作时,要确保操作不会破坏数据库的完整性。如果要插入一个新的学生记录,要检查学号是否唯一(实体完整性),专业编号是否在专业关系表中存在(参照完整性),年龄是否在规定范围内(用户定义完整性)等。
第五章 数据库完整性
一、完整性的分类和相关语句
实体完整性
定义:实体完整性要求每一个表中的主键字段都不能为空或者重复的值。
相关语句(以 SQL 为例):在创建表时,对于定义为主键的列,数据库系统会自动确保实体完整性。例如,创建一个名为 "students" 的表,其中 "student_id" 为主键:
sql
CREATE TABLE students (
student_id INT PRIMARY KEY,
student_name VARCHAR(50),
age INT
);
这里的 "PRIMARY KEY" 约束确保了 "student_id" 列满足实体完整性,即每个 "student_id" 值必须是唯一的,且不能为 NULL。
参照完整性(涉及外键)
定义:参照完整性是指两个表之间的关系。它确保在一个表中的外键值必须与另一个表(被参照表)中的主键值相匹配或者为 NULL(如果外键允许为 NULL 的情况)。
相关语句(以 SQL 为例):假设存在两个表,"orders" 表和 "customers" 表。"orders" 表中的 "customer_id" 是外键,参照 "customers" 表中的 "customer_id"(主键)。
sql
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
customer_name VARCHAR(50)
);
sql
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
这里的 "FOREIGN KEY" 约束确保了 "orders" 表中的 "customer_id" 列的值要么是 "customers" 表中 "customer_id" 列存在的值,要么为 NULL。
域完整性
定义:域完整性确保列中的数据在其定义的有效范围内。这包括数据类型、格式、取值范围等的约束。
相关语句(以 SQL 为例):
对于数据类型的约束,在创建表时就已定义。如:
sql
CREATE TABLE products (
product_id INT PRIMARY KEY,
product_name VARCHAR(50),
price DECIMAL(10, 2) -- 这里定义了price列的数据类型为数值型,总共10位,其中小数点后2位
);
可以使用检查约束(CHECK)来进一步定义取值范围等。例如:
sql
CREATE TABLE employees (
employee_id INT PRIMARY KEY,
employee_name VARCHAR(50),
age INT,
CHECK (age >= 18 AND age <= 65) -- 确保员工年龄在18到65岁之间
);
二、在表中插入或删除数据时,主键、外键如何保证数据完整性
插入数据时
主键
当向一个表中插入数据时,如果表中有主键约束,那么插入的记录的主键值必须是唯一且非 NULL 的。例如,对于前面创建的 "students" 表,如果试图插入两条记录,它们的 "student_id" 值相同,数据库系统将会拒绝插入操作,并抛出错误信息,因为主键的实体完整性不允许重复的主键值。
外键
如果插入的记录包含外键值,这个外键值必须是被参照表中主键值已经存在的值或者为 NULL(如果外键允许为 NULL)。例如,对于 "orders" 和 "customers" 表,当向 "orders" 表中插入一条记录时,"customer_id"(外键)的值必须是 "customers" 表中已有的 "customer_id" 值,或者为 NULL。如果插入一个不存在于 "customers" 表中的 "customer_id" 值,数据库系统会拒绝插入操作,以保证参照完整性。
删除数据时
主键
当从包含主键的表中删除一条记录时,不会直接影响到数据完整性,只要该记录的主键值是唯一且符合其他约束条件的。然而,如果其他表中有外键参照了这个要删除的主键值,可能会引发问题(需要根据数据库系统对外键的处理方式,如设置了级联删除则会同时删除相关记录等情况)。
外键
如果要删除被参照表(主键所在表)中的一条记录,而其他表(外键所在表)中有参照这条记录的外键值,数据库系统会根据设置进行处理。如果没有设置级联删除等特殊处理,默认情况下会拒绝删除操作,因为这样会破坏参照完整性。例如,在 "orders" 和 "customers" 表中,如果要删除 "customers" 表中的一个 "customer" 记录,而 "orders" 表中有记录参照这个 "customer_id",数据库系统默认会阻止这个删除操作。如果设置了级联删除(例如在定义外键时加上 "ON DELETE CASCADE" 选项),那么当删除 "customers" 表中的记录时,"orders" 表中相关的记录也会被自动删除,以保持数据完整性。
三、触发器代码编写(以 MySQL 为例)
(一)创建一个在插入数据前检查数据的触发器
假设我们有一个 "employees" 表,其中 "salary" 列的值不能小于 0。
创建触发器的语法结构
在 MySQL 中,创建触发器的语法如下:
sql
CREATE TRIGGER trigger_name trigger_time trigger_event
ON table_name FOR EACH ROW
BEGIN
-- 触发事件时要执行的代码
END;
其中,"trigger_name" 是触发器的名称,"trigger_time" 可以是 "BEFORE"(在事件之前)或 "AFTER"(在事件之后),"trigger_event" 可以是 "INSERT"、"UPDATE" 或 "DELETE","table_name" 是触发事件所关联的表。
具体的触发器代码
对于我们的 "employees" 表插入数据前检查 "salary" 的情况:
sql
DELIMITER //
CREATE TRIGGER check_salary_before_insert
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
IF NEW.salary < 0 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT ='salary cannot be negative';
END IF;
END //
DELIMITER ;
这里我们首先使用 "DELIMITER" 命令将语句结束符从分号(";")改为双斜杠("//"),因为在触发器代码中的 "BEGIN - END" 块中可能包含多个 SQL 语句,默认的分号结束符会导致语法错误。在触发器内部,我们使用 "IF - THEN" 结构检查要插入的新记录(通过 "NEW" 关键字表示)的 "salary" 值是否小于 0。如果是,则使用 "SIGNAL" 语句抛出一个自定义的错误信息。最后,我们将语句结束符改回分号。
(二)创建一个在更新数据后进行日志记录的触发器
假设我们有一个 "products" 表,每当更新 "products" 表中的数据时,我们要在 "product_updates_log" 表中记录更新的信息(包括更新的时间、更新的字段等)。
创建 "product_updates_log" 表
首先创建记录日志的表:
sql
CREATE TABLE product_updates_log (
log_id INT AUTO_INCREMENT PRIMARY KEY,
product_id INT,
update_time TIMESTAMP,
updated_field VARCHAR(50),
old_value VARCHAR(50),
new_value VARCHAR(50)
);
创建触发器代码
然后创建触发器:
sql
DELIMITER //
CREATE TRIGGER log_product_updates
AFTER UPDATE ON products
FOR EACH ROW
BEGIN
INSERT INTO product_updates_log (product_id, update_time, updated_field, old_value, new_value)
VALUES (
OLD.product_id,
NOW(),
'price' /*这里假设只更新price字段,可根据实际情况修改*/,
OLD.price,
NEW.price
);
END //
DELIMITER ;
在这个触发器中,在 "AFTER UPDATE" 事件发生时,对于 "products" 表中的每一条被更新的记录("FOR EACH ROW"),我们使用 "INSERT" 语句将相关的更新信息插入到 "product_updates_log" 表中。我们通过 "OLD" 关键字获取更新前的值,"NEW" 关键字获取更新后的值,并且获取当前的时间("NOW ()" 函数)来记录更新时间。
第六章 关系设计理论
一、 函数依赖的概念和类型
函数依赖(Functional Dependency,FD):设R(U)是一个属性集U上的关系模式,X和Y是U的子集。若对于R(U)的任意一个可能的关系r,r中不可能存在两个元组在X上的属性值相等,而在Y上的属性值不等,则称"X函数确定Y"或"Y函数依赖于X",记作X→Y。例如在学生选课关系(学号,姓名,课程号,成绩)中,学号→姓名,因为对于每个学号,对应的姓名是唯一确定的。
**完全函数依赖:**在关系模式R(U)中,如果X→Y,并且对于X的任何一个真子集X',都有X'→Y不成立,则称Y对X完全函数依赖。比如在选课关系(学号,课程号,成绩)中,(学号,课程号)\\stackrel{f}{\\longrightarrow}成绩,因为单独的学号或课程号都不能确定成绩。
**部分函数依赖:**若X→Y,但Y不完全函数依赖于X,则称Y对X部分函数依赖。例如在学生关系(学号,姓名,班级,班主任)中,(学号,班级)→班主任,但实际上班级→班主任,所以班主任对(学号,班级)是部分函数依赖。
传递函数依赖:在关系模式R(U)中,如果X→Y,Y→Z,且Y→X不成立,Z∉X,Y∉X,则称Z对X传递函数依赖。例如在学校关系(学校编号,校长,所在城市)中,学校编号→校长,校长→所在城市,且校长不能确定学校编号,所在城市不属于学校编号和校长,所以所在城市对学校编号是传递函数依赖。
二、 函数依赖与关系模式的关系
根据函数依赖可以分析关系模式的合理性和存在的问题。例如存在过多的部分函数依赖和传递函数依赖可能导致数据冗余、更新异常、插入异常和删除异常等问题。
关系模式的范式(Normal Form,NF)
**第一范式(1NF):**如果一个关系模式R的所有属性都是不可分的基本数据项,则R∈1NF。例如关系(学生,课程{语文,数学})就不符合1NF,因为课程属性可以再细分。
**第二范式(2NF):**若关系模式R∈1NF,且每一个非主属性完全函数依赖于码,则R∈2NF。例如在选课关系(学号,课程号,课程名,成绩)中,码是(学号,课程号),课程名只依赖于课程号,对码是部分函数依赖,所以该关系模式不属于2NF。
**第三范式(3NF):**关系模式R<U,F>中若不存在这样的码X、属性组Y及非主属性Z(Z∉Y),使得X→Y,Y→Z成立,则称R<U,F>∈3NF。即消除了非主属性对码的传递函数依赖。例如在关系(学号,专业号,专业名)中,学号→专业号,专业号→专业名,存在传递函数依赖,不属于3NF。
BC范式(Boyce Codd Normal Form,BCNF):关系模式R<U,F>∈1NF,若X→Y且Y∉X时X必含有码,则R<U,F>∈BCNF。它比3NF要求更严格,在BCNF中,每一个决定因素都必须是码。
三、关系模式的分解方法,使其满足更高的范式
分解的原则是保持函数依赖和无损连接。例如将上述选课关系(学号,课程号,课程名,成绩)分解为(学号,课程号,成绩)和(课程号,课程名),前者码为(学号,课程号),后者码为课程号,这样既消除了部分函数依赖,又保持了数据的原有关系。
第七章 数据库设计
一、数据库设计的阶段
**需求分析:**全面了解和收集用户对数据库的需求,包括数据需求、功能需求、性能需求等。例如通过与学校管理人员、教师和学生交流,确定学校数据库需要存储学生信息、课程信息、选课信息等,以及对这些信息的查询、添加、修改、删除等操作需求,和对系统响应时间、数据存储容量等性能要求。
**概念结构设计:**通过对用户需求进行综合、归纳与抽象,形成一个独立于具体DBMS的概念模型,通常用E R图(Entity Relationship Diagram)表示。例如在学校数据库中,确定学生、课程、教师等实体,以及它们之间的选课、授课等关系。
**逻辑结构设计:**将概念结构转换为某个DBMS所支持的数据模型(如关系模型),并对其进行优化。比如将E R图转换为关系表,确定表的结构和表之间的关系。
**物理结构设计:**为逻辑数据模型选取一个最适合应用环境的物理结构(包括存储结构和存取方法)。例如决定学生表的数据是存储在磁盘的哪个位置,采用何种索引方式来提高查询速度。
**数据库实施:**运用DBMS提供的数据语言及其宿主语言,根据逻辑设计和物理设计的结果建立数据库,编制与调试应用程序,组织数据入库,并进行试运行。
**数据库运行和维护:**对数据库进行日常的管理和维护工作,包括数据备份、恢复、性能监控、优化等。
二、手工绘制E R图
**实体:**用矩形表示,矩形框内写明实体名。例如学生、课程等都是实体。
**属性:**用椭圆形表示,并用无向边将其与相应的实体连接起来。如学生的学号、姓名、年龄等是学生实体的属性。
**联系:**用菱形表示,菱形框内写明联系名,并用无向边分别与有关实体连接起来,同时在无向边旁标上联系的类型(1:1、1:n或m:n)。例如学生和课程之间是多对多(m:n)的选课联系。
合并分E R图解决冲突的方法
属性冲突:包括属性域冲突(如属性类型不同,一个是整数型,一个是字符串型)和属性取值单位冲突(如重量一个用千克,一个用克)。解决方法是通过协商统一属性的类型和取值单位。
命名冲突:有同名异义(不同意义的对象有相同名称)和异名同义(相同意义的对象有不同名称)。需要重新命名来消除冲突。
结构冲突:例如同一对象在不同的E R图中有不同的抽象(在一个图中是实体,在另一个图中是属性),或者实体间的联系在不同图中不同。解决方法是根据实际情况进行调整,如将属性提升为实体或修改联系的类型。
E R模型向关系模型转换的原则和方法
实体转换为关系:一个实体转换为一个关系表,实体的属性就是关系表的列。例如学生实体转换为学生表(学号,姓名,年龄等)。
联系转换为关系:
1:1联系:可以将联系合并到任意一端的实体对应的关系表中,也可以单独创建一个关系表,表中包含两个实体的主键。
1:n联系:将1端实体的主键添加到n端实体对应的关系表中作为外键。例如在部门和员工的1:n关系中,将部门主键添加到员工表中。
m:n联系:单独创建一个关系表,表中包含两个实体的主键,并可根据需要添加联系本身的属性。例如学生和课程的选课关系,选课表(学生学号,课程编号,成绩)。
第八章 数据库编程
一、嵌入式SQL
主语言变量和SQL语句的交互
嵌入式SQL是将SQL语句嵌入到高级程序设计语言(主语言)中。在嵌入式SQL中,需要解决主语言变量与SQL语句之间的数据传递问题。例如,在C语言中嵌入SQL语句,当从数据库中查询数据时,需要将查询结果赋值给C语言变量。
通过使用宿主变量(在主语言中定义的变量)来实现交互。宿主变量在SQL语句中通过在变量名前加冒号(:)来标识。例如:
在C语言中定义一个变量int age;,在嵌入式SQL语句中可以这样使用:SELECT name FROM students WHERE student_age > :age;这里的:age就是主语言中的变量。
二、游标程序设计
当SQL查询语句返回多条记录时,需要使用游标(Cursor)来逐行处理结果。
游标操作包括声明、打开、提取数据、关闭等步骤。
- 声明游标:例如DECLARE cursor_name CURSOR FOR SELECT FROM employees;这里cursor_name是游标的名称,该语句定义了一个用于查询员工表所有数据的游标。
- 打开游标:OPEN cursor_name;执行此语句后,游标指向查询结果集的第一行之前。
- 提取数据:FETCH cursor_name INTO :host_variable1, :host_variable2,...;例如FETCH cursor_name INTO :name, :salary;此语句将游标当前指向的行数据提取到相应的宿主变量中。
- 关闭游标:CLOSE cursor_name;在处理完结果集后,关闭游标以释放相关资源。
三.存储过程的编写和调用
存储过程的编写,存储过程是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中。不同的数据库系统有不同的语法来创建存储过程。以MySQL为例,创建一个简单的存储过程来计算两个数的和:
sql
CREATE PROCEDURE add_numbers (IN num1 INT, IN num2 INT, OUT sum_result INT)
BEGIN
SET sum_result = num1 + num2;
END;
这里定义了一个名为add_numbers的存储过程,它接受两个输入参数num1和num2,以及一个输出参数sum_result,功能是计算num1和num2的和并将结果存储在sum_result中。
存储过程的调用
在MySQL中,调用上述存储过程的方式如下:
sql
SET @result = 0;
CALL add_numbers(5, 3, @result);
SELECT @result;
首先初始化一个变量@result用于存储结果,然后使用CALL语句调用存储过程,并将参数传递进去,最后通过SELECT语句查看结果。
第九章 查询优化
1.减少全表扫描
全表扫描是指数据库在执行查询操作时,需要遍历整张表的数据来获取结果。这在数据量较大时会导致性能低下。
例如,在一个有百万条记录的学生表中,如果查询语句是SELECT FROM students WHERE age > 20;而没有对age列建立索引,数据库可能会进行全表扫描来查找满足条件的记录。
2.合理使用索引
索引是一种数据结构,能够帮助数据库快速定位到满足条件的数据。
例如,在学生表的student_id列上建立索引后,当执行SELECT FROM students WHERE student_id = 12345;时,数据库可以通过索引快速找到student_id为12345的学生记录,而不需要扫描整个表。
但索引也不是越多越好,过多的索引会增加数据插入、更新和删除操作的时间,因为每次这些操作都可能需要更新索引。
3.选择合适的连接方法
在涉及多表连接查询时,不同的连接方法(如嵌套循环连接、哈希连接、排序 合并连接等)在不同的数据分布和查询条件下有不同的性能表现。
例如,当连接的两个表较小且连接条件简单时,嵌套循环连接可能比较高效;当数据量较大且适合进行哈希运算时,哈希连接可能更优。
4.查询执行计划的分析方法
大多数数据库管理系统都提供了查看查询执行计划的工具。例如在MySQL中,可以使用EXPLAIN关键字来查看查询语句的执行计划。
例如,执行EXPLAIN SELECT FROM students JOIN courses ON students.course_id = courses.course_id WHERE students.age > 20;会返回查询执行计划,包括使用了哪种连接方式、是否使用索引、扫描了多少行等信息。
通过分析执行计划,可以了解查询语句的性能瓶颈,例如是否进行了不必要的全表扫描,是否没有利用到合适的索引等,进而对查询进行优化。
第十章 数据库恢复
一、 事务的基本概念和特性(ACID)
原子性(Atomicity): 事务是数据库操作的基本逻辑单位,事务中的操作要么全部执行,要么全部不执行。例如在银行转账操作中,从账户A转账1000元到账户B,这个转账操作是一个事务,它包括从账户A扣除1000元(A 1000)和在账户B增加1000元(B + 1000)两个操作,这两个操作必须作为一个整体完成,如果在A 1000操作后系统出现故障,导致B + 1000操作没有执行,那么整个事务将回滚,A的1000元不会被扣除。
一致性(Consistency);事务执行前后,数据库的完整性约束没有被破坏。例如在上述转账事务中,转账前后银行系统的总资金不变,即满足资金总量的一致性。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不能被其他事务干扰。例如有两个事务T1和T2,T1在查询账户余额时,T2不能在T1查询过程中修改账户余额,以保证T1得到准确的查询结果。
持久性(Durability): 事务一旦提交,其对数据库中数据的改变就是永久性的。例如转账事务提交后,即使系统随后出现故障,账户A和账户B的余额变化也会被永久保存。
二、 故障的分类及恢复的基本原理
事务故障
原因:可能是事务内部的逻辑错误,例如在转账操作中,转账金额计算错误。
恢复原理:通过回滚(Rollback)事务来撤销事务中已执行的操作,使数据库恢复到事务开始前的状态。
系统故障
原因:如操作系统故障、数据库管理系统故障、突然断电等。
恢复原理:利用日志文件(Log File)来恢复事务。在系统重启后,对于已提交但还没来得及将修改写入数据库的事务,重新执行(Redo);对于未提交的事务,进行回滚。
介质故障
原因:存储介质损坏,如硬盘损坏。
恢复原理:需要使用数据库的备份(Backup)和日志文件来恢复。首先从备份中恢复数据库到某个时间点,然后根据日志文件将备份之后的事务重新执行或回滚。
第十一章 并发控制
一、并发操作带来的数据不一致性问题
丢失修改(Lost Update)
定义:两个事务和读入同一数据并修改,的提交结果破坏了提交的结果,导致的修改被丢失。
举例:假设事务和都对账户余额进行操作。要从账户中取出元(),要向账户中存入元()。如果先读取的值为,然后读取的值也为。先执行,此时并提交。接着执行,得到并提交。这样的修改就覆盖了的部分修改,的修改效果被丢失了一部分。
读脏数据(Dirty Read)
定义:事务修改某一数据,并将其写回磁盘,事务读取同一数据后,由于某种原因被撤销,这时已修改过的数据恢复原值,读到的数据就与数据库中的数据不一致,则读到的数据就为 "脏" 数据。
举例:事务将账户余额修改为,并写回磁盘。事务读取的值为。然后由于某种原因(如事务违反了某些完整性约束),被撤销,的值恢复为。此时读到的就是脏数据。
不可重复读(Non - Repeatable Read)
定义:事务读取数据后,事务执行更新操作,使无法再现前一次读取结果。
举例:事务读取账户余额的值为。然后事务将的值修改为并提交。如果再次读取的值,就会得到,与第一次读取的不同,这就是不可重复读。
二、并发控制的封锁协议
一级封锁协议
内容:事务在修改数据之前必须先对其加锁(排他锁),直到事务结束才释放。
作用:可以防止丢失修改。因为如果一个事务对数据加了排他锁,其他事务就不能同时对该数据进行修改操作。
二级封锁协议
内容:一级封锁协议加上事务在读取数据之前必须先对其加锁(共享锁),读完后即可释放锁。
作用:除了防止丢失修改外,还可以进一步防止读脏数据。因为如果一个事务对数据加了排他锁进行修改,其他事务不能加共享锁读取(避免读取到未提交的脏数据)。
三级封锁协议
内容:一级封锁协议加上事务在读取数据之前必须先对其加锁,直到事务结束才释放。
作用:在防止丢失修改和读脏数据的基础上,还可以防止不可重复读。因为事务在整个执行期间对读取的数据都加了共享锁,其他事务不能对这些数据进行修改操作,保证了可重复读。