一 简答题:
重点: 第一章(绪论), 第五章(数据库完整性), 第十一章(并发控制)
数据库模型和约束条件:
网状模型:
-
其实就是图
-
约数条件: 插入数据时, 允许插入尚未确定双亲结点值的子女结点值. 删除数据时, 允许只删除双亲结点值. 修改数据时, 可直接表示非树形结构, 而无需像层次模型那样增加冗余结点.
层次模型:
- 本质上就是树形结构
- 约束条件: 在进行插入操作时,如果没有相应的双亲结点值就不能插入它的子女节点值。在进行删除操作的时候,如果删除双亲结点值,则相应的子女节点值也将被同时删除。
数据的完整性包括哪三种?
- 实体完整性
- 参照完整性
- 用户定义完整性
事务:
用户定义的一个数据操作序列, 这些操作要么全部执行, 要么全部不执行, 是一个不可分割的工作单元.
并发操作带来的数据不一致性:
- 丢失更新: 同时读同一数据并修改.
- 读“脏”数据: 读取了未提交事务的数据.
- 不可重复读(幻读现象):两次读同一数据不一样, 另一个事务修改了数据. 并发操作破坏了事务的隔离性.
共享锁(s锁)和排它锁(x锁)的区别:
-
排它锁又称为写锁, 即X锁, 已有X锁或S锁时, 不能加X锁.
- 若事务T对数据对象A加上X锁, 则只允许T读取和修改A, 其它任何事务都不能再对A加任何类型的锁, 直到T释放A上的锁. 这就保证了其它事务在T释放A上的锁之前不能再读取和修改A.
-
共享锁又称为读锁, 即S锁, 只有S锁时, 可加S锁.
- 若事务T对数据对象A加上S锁, 则事务T可以读A但不能修改A, 其它事务只能再对A加S锁, 而不能加X锁, 直到T释放A上的S锁. 这就保证了其它事务可以读A, 但在T释放A上的S锁之前不能对A做任何修改.
封锁协议:
一级封锁协议: 事务T在修改数据R之前必须先对其加X锁, 直到事务结束才释放.
一级封锁协议可防止丢失更新, 并保证事务T是可恢复的.
二级封锁协议: 一级封锁协议加上事务T在读取数据R之前必须先对其加S锁, 读完后即可释放S锁.
二级封锁协议除防止了丢失更新, 还可进一步防止读“脏”数据.
三级封锁协议是: 一级封锁协议加上事务T在读取数据R之前必须先对其加S锁, 直到事务结束才释放.
三级封锁协议除防止了丢失更新和不读‘脏’数据外, 还进一步防止了不可重复读.
死锁:
概念: 有两个或两个以上的线程在执行的过程中, 由于竞争的资源或者彼此通信而造成的一种阻塞状态, 若无外力作用, 他们将都无法进行下去, 从而形成一直阻塞的状态叫死锁.
举例: 某计算机系统中只有一台打印机和一台输入 设备, 进程P1正占用输入设备, 同时又提出使用打印机的请求, 但此时打印机正被进程P2 所占用, 而P2在未释放打印机之前, 又提出请求使用正被P1占用着的输入设备. 这样两个进程相互无休止地等待下去, 均无法继续执行, 此时两个进程陷入死锁状态.
预防死锁: 一次封锁法, 顺序封锁法
死锁诊断: 超时法, 事务等待图法
可串行化调度:
结果正确, 当且仅当其结果与按某一顺序的串行执行的结果相同时, 该策略为可串行化调度策略. 两段锁协议可保证并发调度可串行化.
两段锁协议:
是指所有的事务必须分两个阶段对数据项加锁和解锁. 即事务分两个阶段, 第一个阶段是获得封锁. 事务可以获得任何数据项上的任何类型的锁, 但是不能释放; 第二阶段是释放封锁, 事务可以释放任何数据项上的任何类型的锁, 但不能申请.
注意:
- 遵循两段锁协议,一定可串行化;可串行化,不一定遵循两段锁协议
- 遵循两段锁协议,仍可能发生死锁
二 分析题:
重点: 第二章关系代数
运算符总览:
集合的并, 交, 差, 笛卡尔积运算:
笛卡尔积: 将关系R的每一行分别与关系S的每一行直接连接, 不用管相同属性.
自然连接:
将拥有共同属性的行进等值连接, 其余行舍弃.
外连接:
保留没有共同属性的行(悬浮元组), 并将缺少的部分用null代替.
左外连接: 只保留左边关系表没有共同属性的行.
右外连接: 只保留右边关系表没有共同属性的行.
选择:
选择符合条件的某行或者某几行. 注意是整行. 记为: δ 条件 (表名)
投影:
投整列, 注意去重(若投影完后有两行完全相同, 只保留一行). 记为: π 列名1, 列名2… (表名)
除法:
最后保留R包含而S不包含的属性, 忽视S含有而R不含有的属性. 保留的属性所在行要包含所有共同属性.
可串行化调度判断问题:
可串行化调度: 多个事务的并发执行是正确的, 当且仅当其结果与按某一次序串行地执行这些事务时的结果相同. 可串行化调度当然也保持数据库的一致状态.
通常这种题会给我们几个事务的调度, 然后问我们是否是可串行化调度, 并要求给出判断步骤.
只要我们最后能把给出的调度通过交换事务最后得到一个有序的调度(同一事物的不同操作放在一起), 那么就是可串行化的 (一般题目给的都是可串行化的) .
什么情况下事务不能交换: 1. 不同事务的对同一数据的操作. 2. 同一事物对同一数据的操作.
什么事务可以交换: 不同事务对不同数据的操作. 同一事物对不同数据的操作.
例题: 下列是3个事务的一个调度; Sc1=r3(B)r1(A)w3(B)r2(B)r2(A) w2(B)r1(B)w1(A). 请判断该调度是否为可串行化的调度, 请写出判断的步骤.
- 是可串行化调度.
- 首先交换r1(A)和r3(B), 得到Sc1=r1(A)r3(B)w3(B)r2(B)r2(A) w2(B)r1(B)w1(A).
- 然后交换r3(B)w3(B)和r1(B)w1(A), 得到Sc1=r1(A)r1(B)w1(A)r2(B)r2(A) w2(B)r3(B)w3(B).
- 等价于一个串行调度T1, T2, T3, 所以是可串行化调度.
三 设计题:
重点: 第六章范式, 第七章E-R图
了解范式:
基本概念:
- 候选码: 如果一个集合可以推出所有的属性, 而它的任意一个真子集无法推出所有属性, 那么它就是候选码.
看不懂没事, 看看候选码怎么求的就会了. - 主码: 任意一个候选码都可以当做主码. 在求出候选码后主码是我们自己选择的, 候选码可以有多个, 主码只有一个.
- 主属性: 如果一个属性在某个候选码中出现过, 那么它就被称之为主属性. 注意只要在任意候选码中出现过就可以, 不需要是主码.
- 非主属性: 如果一个属性在任何一个候选码中都没有出现, 那么它就被称之为非主属性.
- 全码: 所有的属性都在候选码中出现过. 也就说所有属性都是主属性.
- 码: 将主码和候选码简称为码.
- 决定因素: 箭头左边的属性. 例如: A→B, 由A能够推出B, A就是决定因素.
函数依赖:
- 完全函数依赖: (A, B)→C且A和B均无法单独推出C, 则C完全依赖于(A, B).
- 部分函数依赖: (A, B)→C且A→C, 则C部分依赖于(A, B). 简单说就是存在非主属性只用主码的一部分就可以推出来.
- 传递函数依赖: A→B & B→C, 如果通过A属性 (属性组) 的值, 可以确定唯一的B属性值, 再通过B属性(属性组)的值可以确定唯一C属性的值, 则称 C 传递依赖于 A. 直观来讲就是存在非主属性可以由非主属性推出来.
四种范式:
- 第一范式: 所有的属性不可再分.
- 第二范式: 在第一范式的基础上, 不存在非主属性对码的部分函数依赖.
- 第三范式: 在第二范式的基础上, 不存在非主属性对码的传递函数依赖.
- 因为二, 三范式都是针对非主属性的, 所以全码可以直接定位到第三范式.
- BCNF范式: 在第三范式的基础上, 不存在主属性对码的部分和传递函数的依赖.
- 判断第三范式是否为BCNF范式: 如果每一个决定因素都包含候选码, 那么就是BCNF.
做题流程:
-
求候选码:
-
依次对照各种范式的条件定位到属于哪种范式.
-
按要求将范式分解到更高级别的范式.
- 如果是存在部分函数依赖, 就将引起部分函数依赖的那部分拿出单独建一个表.
- 如果是存在传递函数依赖, 就将引起传递函数依赖的那部分拿出单独建一个表.
示例:
PS: 下面题目的候选码求的有问题, 应该是C, 主要看做题方法.
画E-R图:
- 实体用矩形括起来.
- 属性用椭圆括起来.
- 关系用菱形括起来.
- 实体间的对应关系要在表上表示出来. 例如: 1对多就要在菱形两边的横线上写1和n.
E-R图转化为关系表:
- 首先将所有的实体分别对应一个关系模式.
- 1对1的实体关系, 将其中一个实体的主码写到另一个实体的关系模式中. 例如: A和B是1对1的关系, 可以将A的主码作为普通的码写到B的关系模式中, B中不用再写A的主码.
- 1对多的实体关系: 将1端实体的主码作为外码写到N端实体的关系模式中并注明是外码.
- 多对多的实体关系: 新建一个关系模式, 模式名是关系名字, 主码是两侧实体的主码. 不要忘记关系的属性.
四 编程题:
重点: 第三章SQL语言
关于建表时数据类型的选择:
- 整形: int
- 浮点数: float(m, n)
- 字符串: varchar(n) 可变长字符串
- 时间: datetime / date 存储日期 + 时间 / 日期
关于什么时候需要加单引号:
整数和浮点数不需要加, 字符串和日期类型均需要加单引号
面向考试SQL语句汇总:
对表的操作:
-
建表
-
create table 表名 (
列名 类型,
列名 类型,
primary key(列名, 列名...), //表示主码
foreign key(列名) references 表名 (列名) //表示外码
foreign key(列名) references 表名 (列名) //一行只能写一个外码
)
-
除了上面的
primary key
和foreign key
之外, 还有三个可以直接跟在类型后面的约束条件: -
not null //不允许为空.
-
unique //不允许重复.
-
cherk(条件) //通常用来指定输入数据的范围, 例如:
grade int cherk(grade >= 0 and grade <=100)
或者sex char(4) cherk(sex = '男' or sex = '女')
-
-
删除表
drop table 表名 cascade
-
添加列
alter table 表名 add 列名 类型
-
删除列
alter table 表名 drop column 列名
-
修改列的类型
alter table 表名 alter column 列名 类型
对数据的操作:
-
添加数据:
insert into 表名 values (,,,)(,,,)(,,,)
-
删除数据:
delete from 表名 where 条件
-
修改数据:
update 表名 set 变量名 = 数据值 where 条件
- 把where和后面的条件去掉就是修改所有人的某个属性
-
排序:
- 排序本质上是对查找到的数据通过比较某个或某几个属性进行排序, 所以要用到selete
selete 列名1, 列名2, 列名3... form 表名 order by 列名2
//order by后只写列名2或者在列名2后加asc, 表示将查找结果按照列名2进行升序排列selete 列名1, 列名2, 列名3... form 表名 order by 列名2 desc
//在列名2后加desc表示将查找结果按照列名2进行降序排列selete * form 表名 order by 列名1, 列名2 desc
//将整个表按照列名1升序排列, 如果列名1相同则按照列名2降序排列
-
查找数据:
-
查找数据是最复杂的一种, 这里只列出几个必考的
-
查找名字中带有吴的人的名字:
selete 列名1 from 表名 where 列名1 like '%吴%'
// %是匹配任意字符串 -
查找员工名和公司名(分别在员工表和公司表, 两个表的共同列是公司编号):
selete 员工表.名字列, 公司表.公司列 from 员工表, 公司表 where 员工表.公司编号 = 公司表.公司编号
//更多的表和两个表一个道理 -
简单举例三张表查询(其实和两张表一样): 有三个表 a b c. c.aid对应a.aid, c.bid对应b.bid对应a.aid, c.bid对应b.bid, 现在要查出a.aname,b.bname,c.value.
select a.anme, b.bname, c.value
from a,b,c
where a.aid = c.aid and b.bid = c.bid
-
统计总人数大于2的各班级各性别人数, 列出班级, 性别, 人数:
-
select 班级列, sum(case when 性别列 = '男' then 1 else 0 end) as 男生人数, sum(case when 性别列 = '女' then 1 else 0 end) as 女生人数
from 班级表
group by 班级列
having (count(班级列) > 2);
-
视图的建立:
-
视图的建立和表类似
-
create view 视图名 as
select 列名1, 列名2, 列名3...
form 表名
where 条件
with check option