概念:数据模型(Data Model)也是一种模型,他是对现实世界数据特征的抽象。数据模型就是现实世界的模拟
两类数据模型
概念模型(信息模型):按照用户的观点来对数据和信息建模,主要用于数据库设计。
逻辑模型和物理模型
逻辑模型主要包括:
他是按计算机系统的观点对数据建模,主要用于DBMS的实现
物理模型是对数据最低层的抽象,它描述数据在系统内部的表示方式和存取方式,在磁盘或者磁带上的存储方式和存储方法,是面向计算机系统的
数据模型的组成要素
由三部分组成
数据结构:数据结构描述数据库的组成对象以及对象之间的练习,数据结构是所描述的对象类型的集合,是对系统静态特性的描述
数据操作:查询和更新(增删改),是对系统动态特性的描述
完整性约束:是一组完整性规则
概念:概念模型是现实世界到机器世界的一个中间层次,表现为:
要求:
信息世界中的基本概念
实体:客观存在并且可以相互区分的事物,比如学生,教师,部门,课都是实体
属性:实体具有的特征,例如学生的学号姓名年龄等等
码:唯一标识实体的属性或属性集,例如学号是学生的码
域:属性的取值范围,比如政治成绩的范围为0-100
实体型:具有相同属性的实体肯定有共同的特征和性质,比如学生(学号,性别,姓名,出生日期)就是一个实体型
实体集:全体学生就是实体集
联系:实体内部的联系(组成实体的属性间的关系),和实体间的联系(不同实体集的联系)
一对一联系:
一对多联系:
多对多联系:
注意:不要忽略实体内部的联系,比如职工中有领导与被领导的关系,所以ER图可以画为
概念模型的一种表示方法:ER图
常见的模型:
关系模型的数据结构
优点:
模式: 数据模型中有“型”和“值”的概念,如:学生(学号,性别,班级)是“型”,而:张三(20160310001,1,3年2班)是“值”。 模式(Schema)是数据库中全体数据的逻辑结构和特征的描述,它仅仅描述型,而并不包括值。模式的值称为模式的一个实例(Instance),同一个模式可以有多个实例。
三级模式:
两级映射: 这两层映像保证了数据库中的数据能够具有较高的逻辑独立性和物理独立性。
概念:从用户角度来说,关系模型中数据的逻辑结构是一张二维表,关系模型是建立在集合代数的基础上
相关定义:
域:具有相同数据类型的值的集合
笛卡儿积:给定一组域D1 D2…Dn这n个取值范围(域),所有域的所有取值的一个组合,会产生在现实生活中无实际意义的数据
关系:
三类关系
基本关系的性质
概念:关系模式是对关系的描述,关系模式是型,关系是值
关系模式表示方式:R(U,D,DOM,F) 区别于关系的表示方式
关系模式和关系:
常用的关系操作:
特点: 是集合操作方式,即操作的对象和结果都是集合
关系运算包括:选择,投影,连接,除运算
相关计号说明:
姓名 | 成绩 | 性别 |
---|---|---|
何佳乐 | 100 | 男 |
李四 | 90 | 男 |
王五 | 90 | 男 |
例如:性别男,在关系上的象集为:{(张三,100),(李四,90),(王五,90)}
成绩90,在关系上的象集为:{(李四,男),(王五,男)}
成绩90,性别男,在关系上的象集为:{李四,王五}
选择: (从行的角度进行的运算) , 选择运算是根据某些条件挑选出元组(即行)
投影
连接(连接运算为=的称为等值连接):
等值连接
自然连接,是一种特殊的等值连接(就是等值连接中去掉两表相同的属性列,符号一样,但是符号下面不写任何比较符号)
概念:结构化查询语言,是关系数据库的标准语言,SQL是一个通用的,功能极强的关系数据库语言
特点:
基本概念:SQL支持关系数据库三级模式结构
定义基本表:如果完整性约束条件涉及到该表的多个属性列,则必须定义在表级上,否则既可以定义在列级上也可以定义在表级上
varchar和char的区别
numeric(p,d):定点数,总长p位,小数点后d位
模式与表:
创建基本表
创建表的时候给出模式名
在创建模式语句中同时创建表
设置所属模式,在创建表名中不必给出模式名–直接写创建表的语句就可以
修改基本表
删除基本表:drop table tableName cascade/restrict
建立索引
语法格式:create [unique] [cluster] index<索引名> on <表名>(列名)
删除索引:
语法格式:
select [all/distinct]
目标列
from
表名或视图名列表
where
条件列表
group by
列名
having
分组之后的条件
order by
排序的列名 asc/desc
limit
分页限定
查询满足条件的元组
比较:> < >= <= !>
确定范围:between and,not betweenk
-- 查询年龄在【20,23】之间的学生姓名和部门
select
sname,sdept
from
student
where
sage between 20 and 23
确定集合:in ,not in
-- 查询信息系,数学系,和计算机系的学生的姓名和性别
select
sname,sdept
from
student
where
dept in('is','ma','cs');
字符匹配:like,not like --%和_
-- 查询姓张的学生的详细信息
select
*
from
student
where
sname like '张%';
-- 查询DB_Design课程的课程号和学分
select
cno,credit
from
course
where
cname like 'DB\_Design' ESCAPE '\';
-- ESCAPE '\'表明\是转码字符,将通配符转义为普通字符
-- 查询以'DB_'为开头,且倒数第三个字符为i的课程的细致情况
select
*
from
course
where
cname like 'DB\_%i__' escape '\';
--
空值:is null ,is not null
-- 涉及空值的查询,比如,有的学生没有参加某一门考试,如果不对这个null进行处理的话,则该学生的
-- 总成绩也会是null,这是不合理的
select
name,math,english,math+ifnull(english,0)
from
stu2
-- ifnull(X,Y)函数,若X为null,则以Y值替换之
--
多重运算(逻辑运算):and,or,not,and的优先级高于or,所以推荐有逻辑运算的时候加上括号
取消重复行(distinct),不写则默认all
order by
-- 查询选秀了3号课程的学生的学号以及成绩,查询结果按分数降序排列
select
sno,grade
from
sc
where
cno='3'
order by
grade desc;
-- 查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列
select
*
from
student
order by
sdept asc,age desc;
聚集函数(所有的都有可选项DISTINCT |all)
group by子句:按指定的一列或多列的值分组,值相等的为一组,来细化聚集函数的作用对象
未对查询结果分组,聚集函数将作用于整个查询结果
对查询结果分组后,聚集函数将分别作用于每个组
-- 求各个课程号及其相对应的选课人数
select
cno,count(sno) as 人数
from
sc
group by cno
-- 求选修了3门以上课程的学生学号
select
sno
from
sc
group by
sno
having
count(cno)>3
注意:一旦使用了分组,那么查询的列,要么时分组时依据的列,要么是聚集函数
having和where子句的区别:
作用对象不同:where作用于基表或者视图,从中选择满足条件的元组,having作用于分组,从中选择满足条件的组,having是和group by连在一起的
where子句中是不可以用聚集函数作为条件的
-- 查询平均成绩大于等于90分的学生学号和平均成绩
-- 下面是错误写法
select
sno,avg(grade)
from
sc
where avg(grade)>90;
-- 下面是正确写法
select
sno,avg(grade)
from
sc
group by
sno
having
avg(grade)>90;
等值连接和非等值连接查询:进行连接操作的时候,系统并不会生成一个真正的大表,而是在查询的时候才有,查询完就销毁
注意:
-- 查询每个学生以及其选修课程的情况
select
student.*,sc.*
from
student,sc
where
student.sno=sc.sno;
连接操作的执行方法(了解):嵌套循环法
自身连接:一个表与其自己进行连接
注意
例如:查询每一门课的间接先行课,即先修课的先修课
select
t1.cno,t2.cpno
from
course t1,course t2
where
t1.cpno=t2.cno;
外连接
多表连接:连接操作是两个以上的表进行连接
-- 查询每个学生的的学号,姓名,选修的课程名以及成绩
select
t1.sno,t1.sname,t2.cname,t3.grade
from
student t1,course t2,sc t3
where
t1.sno=t3.sno and t2.cno=t3.cno
嵌套查询:是指将一个查询块嵌套在另一个查询块的where子句或者having子句的条件中查询
注意:
子查询的不同情况
子查询的结果是单行单列的
salary
< (SELECT AVG(salary) FROM emp);子查询的结果是多行单列的
SELECT * FROM emp WHERE dept_id IN (SELECT id FROM dept WHERE NAME='财务部' OR NAME='市场部');
子查询的结果是多行多列的
-- 查询员工的入职日期是2011年11月11日之后的员工信息和部门信息` `SELECT * FROM dept t1,(SELECT * FROM emp WHERE emp.join_date>'2011-11-11') t2 WHERE t1.id=t2.dept_id;
any和all
>any 大于子查询的结果的某个值
\>all 大于子查询结果的全部值
-- 查询非计算机科学系中比计算机科学任意一个学生年龄小的学生姓名和年龄
select
sname,age
from
student
where
age<any(select age from student where dept='cs'
and
sdept<>'cs';
带有exists谓词的子查询
exists为此代表存在量词,带有exists谓词的子查询只返回逻辑真值true或逻辑假值false
-- 查询所有选修了1号课程的学生姓名
select
sname
from
student
where exists
(select * from sc where sno=student.sno and cno='1')
使用存在量词后,若内层查询结果为非空,则外层的where子句返回真值;否则返回假值
由exists引出的子查询目标列表都用*,因为带exists的子查询只返回真值或假值,给出列名无实际意义
不同形式的查询间的替换
一些带exists或not exists谓词的子查询不能被其他形式的子查询等价替换
所有带in谓词,比较运算符,any和all谓词的子查询都可以用带exists谓词的子查询等价替换
上面都太过于抽象,不好理解
exists就是提交匹配到的
not exists 就是提交匹配不到的
-- 查询选修了全部课程的学生--
select
sname
from
student
where
sno in
(
select
sno
from
sc
group by
sno
having
count(*)=(select count(*) from course)
);
-- 查找学号为00003的学生没有选修的课程
select
cname
from
course
where not exists
(
select
*
from
sc
where
course.cno=sc.cno and sno='00003'
)
-- 查询与刘晨在同一个系的学生
select
sno,sname,sdept
from
student s1
where exists(
select
*
from
student s2
where
s1.sdept=s2.sdept and s2.sname='刘晨'
);
/*
从这个题目,我们要搞懂exists的执行流程
1.首先,将外层查询的第一行带入子查询
2.若子查询返回真,则输出这一行元组对应的列
3.若子查询返回假,则不输出这一元组
4.代入下一元组,循环往复执行
*/
-- 查询选修了全部课程的学生姓名
用exists实现全称量词
首先插入一个高中知识:命题的否定(是求补集而不是反面)
全称命题转换为同意义的存在命题,就是先进行全称命题的否定,然后再否定就可以
所以查询选修了全部课程的学生–>学生选修了全部的课—>存在一门课学生没有选修—>没有一门课是学生没有选修的—>没有一门课是他不选修的
-- 查询选修了全部课程的学生姓名 等价于 没有一门课是他不选修的
select
sname
from
student
where not exists(
select * from course
where not exists(
select * from sc
where sno=student.sno and cno=course.cno
)
)
用exists实现逻辑蕴涵p->q=!p或q
-- 查询至少选修了学生201215122选修的全部课程的学生学号
-- 等价于不存在这样的课程y,学生201215122学修了y而学生x没有选
并操作:
-- 查询计算机系的学生以及年龄不大于19岁的学生
-- 方法一
select
sno
from
student
where
age<=19 or dept='cs';
-- 方法二,使用并操作
select sno from student where dept='cs'
union
select sno from student where age<=19;
交操作 intersect(mysql无此操作)
-- 查询计算机科学系的学生,且不大于19岁的学生
select * from student where dept='cs'
intersect
select * from student where age<=19;
-- 查询即选修了一号课程,又选修了二号课程的学生
-- 方法一,使用集合操作
select sno from sc where cno=1
intersect
select sno from sc where cno=2;
-- 方法二,使用自身连接
select
t1.sno
from
sc t1,sc t2
where
t1.sno=t2.sno and t1.cno=1 and t2.cno=2;
-- 方法三,嵌套查询:多行单列的查询结果--使用in
select
sno
from
sc
where
cno=1 and sno in (select sno from sc where cno=2)
差操作Except
-- 查询计算机系的学生与年龄不大于19岁的学生的差集
-- 方法一:使用差操作
select * from student where dept='cs'
except
select * from student where age<=19;
-- 上述例子其实是在查询:是计算机系的学生,且年龄大于19岁
-- 方法二:and操作 略
就是子查询不仅可以出现在where子句中,也可以出现在from子句中,对应的就是多行多列的子查询,此时子查询生成的表称为临时派生表,成为主查询的查询对象
-- 找出每个学生超过他自己选修课程平均成绩的课程号
SELECT
t1.sno,t1.cno
FROM
sc t1,(SELECT sno,AVG(grade) AS a FROM sc GROUP BY sno) t2
WHERE
t1.sno=t2.sno AND t1.grade>t2.a;
插入元组:
insert into 表名[<属性列>] values (数据)
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('孙空','男',7200,'2013-02-24',1);
插入子查询的结果
insert into 表名[<属性列>] select子句
-- 求学生的平均年龄,并且把结果存入表中
-- 1.建表
create table dept_age(
dept char(15), -- 系名
avg_age int -- 学生平均年龄
);
-- 2.插入数据
insert into dept_age (dept,avg_age)
select
dept,avg(age)
from
stduent
group by
dept;
-- 语句格式
update <表名>
set 列名1=数据,列名2=数据,列名3=数据
where 条件;
-- 1.修改一个元组:将学生200215121的年龄改为22岁
update
student
set
sage=22
where
sno='200215121';
-- 2.修改全部元组:将所有学生的年龄增加一岁
update
student
set
sage=sage+1;
-- 3.带子查询的修改语句:将计算机科学系全体学生的成绩清零
update
sc
set
grade=0
where
sno in(
select sno from student where sdept='cs'
);
-- 1.删除一个元组:删除学号为201015121的学生记录
delete from
student
where
sno=201015121;
-- 2.删除多个元组的值:删除所有学生的选课记录
delete from sc;
-- 3.带子查询的删除语句:删除计算机科学系所有学生的选课记录
delete from
sc
where sno in(
select sno from student where dept='cs'
);
一般有以下的情况:
空值的产生:插入的时候没插入该行的数据
空值的判断:用is null 或is not null
-- 从student表中找出漏填了的数据
select * from student where sname is null or sex is null or sdept is null;
空值的约束条件
空值的算数运算,比较运算与逻辑运算
建立视图
语法格式
-- 1.建立计算机系学生的视图
create view
cs_student -- 视图名
as
select sno,sname,sage from student where sdept='cs'; -- 子查询
-- 2.建立计算机系学生的视图,并要求进行修改和插入操作时仍保证该视图只有计算机系的学生
create view
cs_student -- 视图名
as
select sno,sname,sage from student where sdept='cs'
with check option; -- 对其数据更新的时候要检查其完整性 where sdept='cs'
说明:
在第二个例子中,加上了with check option ,所有DBMS对该视图进行更新操作的时候
建立基于多个基表的视图
-- 建立信息系中,选修了1号课程的学生视图
create view is_s1(sno,sname,grade)
as select student.sno,sname,grade from student,sc where student.sno=sc.sno and sc.cno='1';
基于视图的视图
-- 建立-信息系选修了1号课程且成绩在90分以上的学生视图
create view is_s2
as
select sno,sname,grade from is_s1 where grade>=90;
带表达式的视图
-- 定义一个反映出学生出生年份的视图
create view bt_s(sno,sname,sbirth)
as
select sno,sname,2020-sage as 出生日期 from student
分组视图
-- 将学生的学号以及他的平均成绩定义为一个视图
create view s_g(sno,gavg)
as
select sno,avg(grade) from sc group by sno;
删除视图
说明:
-- 删除视图bt_S
drop view bt_S;
-- 删除视图is_s1,但是is_s1的基础上还导出了视图is-s2,所以要使用级联删除
drop view is_s1 cascade;
RDBMS实现视图查询的方法—视图消解法
进行有效性检查
转换成等价的对基本表的查询
执行修正后的查询
-- 在信息系学生的视图里找到年龄小于20岁的学生
select sno,sage from is_student where sage<20
-- 转换后
-- 因为在创建视图的时候,使用了with check option
select sno,sage from student where sdept='is' and sage<20;
2.视图消解法的弊端
非授权用户对数据库的恶意存取和破坏(例如黑客)
数据库中重要或者敏感的数据被泄露
安全环境的脆弱性(包括计算机硬件,操作系统,网络系统等的安全性)
计算机系统的安全模型–计算机系统中安全措施是一级一级层层设置
数据库安全性包括:
存取控制流程
grant
grank 权限 on 对象 to 用户 [with grant option]
-- 把查询student表的权限授予给用户u1
grant
select on table student
to
u1;
-- 把对象SC的查询权限授予所有用户
grant
select on table sc
to
public
-- public 代表所有用户
-- 把查询student表和修改学生学号的权限给用户u4
grant
update(sno),select on table student
to
u4;
-- 对属性列的授权的时候必须明确指出相对于的属性列名
-- 把对表sc的inster权限授予给u5,并允许他再把改权限授予别人
grant insert
on table sc
to u5
with grant option;
revoke
revoke 权限 on 类型 对象名 from 用户 cascade|restrict
-- 把用户u4修改学生学号的权限收回
revoke update(sno)
on table student
from u4;
-- 收回所有用户对表sc的查询权限
revoke select
on table sc
from public;
-- 把用户u5对sc表的insert权限收回
revoke insert
on table sc
from u5 cascade;
-- 因为使用了cascade,u6和u7的权限一同被收回
角色创建
给角色授权
将一个角色授予其他的角色或用户
角色权限收回
-- 通过角色实现将一组权限授予一个用户
-- 1. 首先创建一个角色R1
create role R1
-- 2. 然后使用grant语句,使角色R1拥有student表的select,update,insert权限
grant select,update,insert
on table student
to R1;
-- 3. 将这个角色授予王平,张明,赵玲,使他们具有角色R1所包含的全部权限
grant R1 to 王平,张明,赵玲;
-- 4. 可以一次性通过R1来回收王平的这三个权限
revoke R1 from 王平;
自主存取控制的缺点:
MAC
视图对数据库安全的作用
-- 建立计算机系学生的视图,把对该视图的select权限授予王平,把该视图上的所有操作权限授予张明
-- 1. 先建立计算机系学生的视图cs_student
create view cs_student
as
select * from student where sdept='cs';
-- 2. 在视图上给王平老师授予检索计算机系学生信息的权限
grant select
on cs_studeng
to 王平;
-- 3. 在视图上所有的权限授予系主任张明
grant all priviliges -- [all priviliges代表授予全部权限]
on cs_student
to 张明;
概念:
审计功能是可选的
审计事件
审计功能(略)
审计分类
audit语句和noaudit语句
-- 对修改sc表结构或修改sc表数据的操作进行审计
audit alter update
on sc;
-- 取消对sc表的一切审计
noaudit alter,update
on sc;
说明:
存储加密:
传输加密
DBMS可信传输步骤
-- 在列级定义主码,只适用于单属性主码
create table student(
sno char(9) primary key,
sname char(20) not null,
ssex char(2),
sage smallint,
sdept char(20)
);
-- 在表级定义主码
create table student(
sno char(9),
...
sdept char(20),
primary key(sno) -- 表级定义主码,括号内可以有多个属性
);
-- 如果是在sc表中,则必须是表级定义,因为主码是由sno和cno构成的,定义如下
primary key(sno,cno)
-- 定义sc表中的参照完整性
create table sc(
sno char(9) not null,
cno char(4) not null,
grade smallint
primary key(sno,cno), -- 表级定义主码
foreign key(sno) references student(sno), -- 表级定义参照完整性
foreign key(cno) references course(cno) -- 表级定义参照完整性
);
被参照表(student) | 参照表(SC) | 违约处理 |
---|---|---|
可能破坏参照完整性 | 插入元组 | 拒绝(默认策略) |
可能破坏参照完整性 | 修改外码值 | 拒绝 |
删除元组 | 可能破坏参照完整性 | 拒绝/cascade删除/设置为空值 |
修改主码值 | 可能破坏参照完整性 | 拒绝/cascade修改/设置为空值 |
-- 在创建表的时候定义违约处理
create table sc(
sno char(9) not null,
cno char(9) not null,
grade smallint,
primary key(sno,cno),
foreign key(sno) references student(sno)
on delete cascade -- 定义外键sno级联删除
on update cascade, -- 定义外键sno级联更新
foreign key(cno) references course(cno)
on delete no action -- 定义外键cno拒绝删除执行
on update cascade, -- 定义外键cno级联更新
);
create table test(
sno char(9) not null,
cno char(9) not null, --若cno是主码,可以不设置not null
dname char(9) unique not null, -- 设置唯一且非空
ssex char(2) check(ssex in('男','女')), -- 性别只可以取男或女
grade smallint check(grade>=0 and grade<=100>) -- 成绩的取值范围是0-100
)
-- 当学生的性别时男时,其名字不可以是Ms.打头
create table student(
sno char(9),
same char(8) not null,
...
primary key(sno),
check(ssex='女' or sname not like 'Ms%') --定义了元组中sname和ssex两个属性值之间的约束条件
)
-- 建立学生登记表student,要求学号在90000-99999之间,姓名不可以取空值,年龄小于30,性别只可以是男或女
create table student(
sno numeric(6) student constraint c1 check(sno between 90000 and 99999)
sname char(20) constraint c2 not null,
sage numeric(3) constraint c3 check(sage<30),
ssex char(2) constraint c4 check(ssex in('男','女')),
constraint c5 primary key(sno)
);
-- 去掉上例中对性别的限制
alter table student
drop constraint c4;
-- 修改上例student中的约束条件,要求学号改为在900000-999999之间,年龄由小于30改为小于40
-- 可以删除原来的,再增加新的约束条件
alter table student drop constraint c1;
alter table student add constraint c1 check (sno between 900000 and 999999),
alter table student drop constraint c3;
alter table student add constraint c3 check(sage<40)
-- 建立一个性别域,并声明性别域的取值范围
create domain GenderDomain char(2) check(value in('男','女'));
-- 可以再创建表的时候使用GenderDomain定义性别属性
ssex GenderDomain,
-- 建立一个性别域,并对其中的限制命名
create domain GenderDomain char(2)
constraint c1 check(value in('男','女'))
-- 删除域GenderDomain的限制条件c1
alter domain GenderDomain
drop constraint c1;
-- 在域GenderDomain上增加性别的限制条件c2
alter domain GenderDomain
add constraint c2 check(value in('1','0'));
-- 限制数据库课程最多60名学生选修
create assertion a1 check(
60>=select count(*) from course,sc where sc.cno=course.cno and course.cname='数据库')
);
-- 限制每一门课最多60名学生选修
create assertion a2 check(
60 >= all (select count(*) from sc group by cno)
);
-- 限制每个学期,每一门课程最多60名学生选修
-- 1. 首先,需要修改sc表的模式,增加一个'学期(TERM)'属性
alter table sc add term date;
-- 2. 然后,定义断言
create assertion a2 check(60>= all (select count(*) from sc group by cno,term));
create trigger 触发器名
{before|after} 触发事件 on 表名 -- before和after 指触发器执行是在触发事件之前还是之后,触发事件一般是增删改
referencing new|old row as 变量 -- new|old代表修改前还是后的数据 ,赋予给变量
for each{row|statement} -- row|statement代表是行还是语句
[when 触发条件]触发动作
-- 当对表sc的grade属性进行修改时,若分数增加了10%,则将此次操作记录到下面的表中:
-- sc_u(sno,cno,oldgrade,newgrade)
-- 其中,oldgrade是修改前的分数,newgrade是修改后的分数
-- 设计触发器
create trigger sc_t -- 创建一个触发器,触发器名为:sc_t
after update of grade on sc -- 当sc表上对grade属性发生update后,激活触发器
referencing
old row as OldTuple -- 将旧的行赋予变量名:OldTuple
new row as NewTuple -- 将新的行赋予变量名:NewTuple
for each row -- 行级触发器
when(NewTuple.grade>=1.1*OldTuple.grade) -- 当新行中的成绩是旧行中成绩的1.1倍时,执行触发器
insert into sc_u(sno,cno,oldgrade,newgrade) -- 下面就是一个插入语句,将指定的信息插入到sc_u表内
values(OldTuple.sno,OldTuple.cno,OldTuple.grade,NewTuple.grade)
-- 将每次对表student的插入操作所增加的学生个数记录到表studentInsertLog中
create trigger student_count
after insert on student
referencing
new table as delta
for each statement
insert into studentInsertLog(numbers)
select count(*) from delta
一个数据表上可能定义了多个触发器,遵循如下的顺序
删除触发器的语法:
drop trigger 触发器名 on 表名
触发器必须是一个已经创建的触发器,并且只能由具有相应权限的用户删除
一些术语和记号
概念:设计数据库的时候,需要遵循的一些规范。
了解一些课本知识
首先说明,键字=码字,所以主关键字=主码=主键,候选键=候选码=候选关键字
各种码:
候选码/超级玛:可以唯一的表示一个元组的属性或者属性集,一个表可以有多个候选码,例如学生表(学号,姓名,身份证),那么学号可以作为候选码,身份证也可以作为候选码
主码:从候选码中人为的挑选一个作为主码,例如上面的学生表中,我们可以选择学号作为主码,也可以选择身份证号作为主码
主属性:包含在任意候选码中的属性为主属性,例如学号和身份证就是主属性
非主属性:姓名就是非主属性
全码:当所有的属性共同构成候选码的时候,称该码为全码
码/超键/键:可以唯一标识一条记录的属性或者属性集,即含有候选码就行,例如(学号,姓名)是一个码,(姓名,身份证)是一个码。
表
Armstrong公理系统是一套推理规则,是模式分解算法理论的基础,主要用于求给定关系模式的码,从一组函数依赖求得蕴涵的所有函数依赖,该公理系统包含以下的1,2,3
在关系模式R中,为F所逻辑蕴涵的函数依赖的全体叫做F的闭包,记作F+
如果题目要求,求出(AB)+,那么首先,将(AB)分成A,B,AB,然后在函数依赖全体中找,是否有函数依赖的左边为A,B,AB,如果有,就将他的右边写出,例如A->C,AB->E,那么我们可以将CE加入AB,那么下一步,我们应该将(ABCE)分为A,B,C,E,AB,AC,AE,BC,BE…然后去函数依赖集中找左边是否有相等的,然后把右边的属性写出并加入,结束条件是有两个,1是发现这一次的结果和上一次一样,那么说明已经无法扩充了,停止,2是发现当前已经包含了全部属性,那么也可以停止了
数据库设计分为六个阶段
参加数据库设计的人员
各阶段主要任务
各个阶段的数据设计描述
设计阶段 | 设计描述 |
---|---|
需求分析 | 数据字典,全系统中数据项,数据结构,数据流,数据存储的描述 |
概念结构设计 | 概念模型(ER图),数据字典 |
逻辑结构设计 | 某种数据模型,比如关系型数据模型和非关系(树,网)数据模型 |
物理结构设计 | 存储安排,存储方法选择,存储路径选择 |
数据库实施 | 创建数据库模式create…,装入数据,数据库试运行 |
数据库运行和维护 | 性能监测,转储/恢复,数据库重组和重构 |
概念模型的描述工具:E-R模型
ER图:ER图提供了表示实体型,属性和联系的方法
概念结构设计
内容:为关系模式选取存取方法(建立存取路径)以及设计关系,索引等数据库文件的物理存储结构
常见的存取方法:
B+树索引存取方法
Hash索引存取方法:如果一个关系的属性主要出现在等值连接条件中或主要出现在等值比较选择条件中,而且满足下面条件之一:
聚簇存取方法:是为了提高某个属性或属性组的查询速度,把这个或这些属性(称为聚簇码)上具有相同值的元组,存放在连续的物理块中称为聚簇.
数据库的重组织与重构造
通信区的定义:EXEC SQL INCLUDE SQLCA;
主变量:嵌入式sql语句中可以使用主语言的程序变量来输入或输出数据,在SQL语句中使用的主语言程序变量,简称为主变量
begin declare section
...
...(说明主变量和指示变量,主语言怎么定义变量,这里就怎么写)
...
end declare section
游标:
建立和关闭数据库连接:
-- 依次检查学生记录,交互式更新某些学生的年龄
EXEC SQL BEGIN DECLARE SECTION;-- 主变量说明开始,以下声明的都是主变量
char Deptname[20]; -- 系名
char HSno[9]; -- 学号
char HSname[20]; -- 姓名
char HSsex[2]; -- 性别
int HSage; -- 旧的年龄
int NEWAGE; -- 要设置的新的年龄
EXEC SQL END DECLARE SECTION; -- 主变量的声明结束
long SQLCODE; -- 存放每次执行SQL语句后返回的结果的代码
EXEC SQL INCLUDE SQLCA; -- 定义sql通信区
int main(void){ /*c语言主程序开始*/
int count=0;
char yn; //
printf("please choose the department name(CS/MA/IS");
scanf("%s",Deptname); //为主变量deptname赋值
EXEC SQL CONNECT TO TEST@localhost:54321 USER "SYSTEM/MANAGER" ; //连接数据库
// 意思就是要用SYSTEM/MANAGER用户访问localhost计算机上的TEST数据库
}
EXEC SQL DECLARE SX CURSOR FOR -- 定义一个名字叫SX的游标
select Sno,Sname,Ssex,Sage -- 定义游标对应的SQL语句,该sql语句查询的结果会放入游标的缓冲区里面
from Student
where Sdept=:Deptname; -- where子条件是查询Deptname的系,这个Deptname是主变量,在sql里面用
-- 主变量,为表示和sql表进行区分,变量名前加冒号:
EXEC SQL OPEN SX; -- 打开游标SX,指向查询结果第一行
for( ; ; ){ // 使用for循环逐条处理结果集中的记录
EXEC SQL FETCH SX INTO :HSno,:HSname,:HSsex,:HSage;
// 推进游标,将sql中查询到的元组的数据,存放到主变量里面
if(SQLCA.SQLCODE!=0)
break; // 表示如果操作不成功,则推出for循环
if(count++==0) //如果是第一行的话,先输出行头
printf("\n%-10s %-20s %-10s %-10s\n","Sno","Sname","Ssex","Sage");
printf("\n%-10s %-20s %-10s %-10s\n",HSno,HSname,HSsex,HSage) // 打印查询结果
printf("UPDATE AGE(Y/N)?"); // 询问用户是否要更新该学生的年龄
do{
scanf("%c",&yn);
}while(yn != 'N' && yn != 'Y' && yn != 'y' && yn != 'n') //输入字符不合法
if(yn == 'y'|| yn == 'Y'){ //如果用户选择修改年龄
printf("input new age:");
scanf("%d",&NEWAGE);
EXEC SQL UPDATE Student
SET Sage=:NEWAGE
WHERE CURRENT OF SX; // 该where条件子句的意思是当前游标指向的那一行元组
}
}
EXEC SQL CLOSE SX; // 关闭游标,不再和查询结果对应
EXEC SQL COMMIT WORK; // 提交更新
EXEC SQL DISCONNECT TEST; // 断开数据库连接
-- 1. 查询结果为单记录的select语句
EXEC SQL SELECT sno,sname,ssex,sage,sdept
into :hsno,:hsname,:hssex,:hsage,:hsdept
from student
where sno=:givensno;
-- 2. 查询某个学生选修某门课程的成绩,假设我们已经把将要查询的学生的学号赋值给了主变量givensno,将课程号赋值给了主变量givencno
EXEC SQL SELECT sno,cno,grade
into :hsno,:hcno,:hgrade:gradeid -- gradeid成绩主变量上的一个指示变量
from student
where sno=:givensno and cno=:givencno;
-- 如果gradeid<0,不论Hgrade为何值,均认为该学生成绩为空值
-- 1. 查询某个学生选修一号课程的成绩
EXEC SQL UPDATE SC
SET GRADE=:newgrade
where sno=:givensno;
-- 2. 某个学生新选修了某门课程,将有关记录插入sc表中,假设插入的学号已经赋值给主变量stdno,课程号已经赋值给主变量couno
gradeid=-1; //gradeid为指示变量,赋为负值
EXEC SQL INSERT
INTO SC(SNO,CNO,GRADE)
VALUES(:stdno,:couno,:gr:gradeid);
-- 由于该学生刚选修课程,成绩应该为空,所以要把指示变量设为负值
静态嵌入式sql:可以满足一般要求,无法满足要到执行时才能够确定要提交的sql语句,查询的条件(就是说sql语句在编程序的时候,该语句结构已经固定了,可能where子句之类的会变,但是结构不会变)
动态嵌入式sql:在程序运行过程中可以临时组装sql语句,支持动态组装sql语句和动态参数两种形式
exec sql begin declare section;
const char *stmt="create table test(a int);" -- sql语句主变量,内容是创建表的sql语句
exec sql end declare section;
...
exec sql execute immediate:stmt; --执行动态sql语句,结果就是在数据库里面建立了一个test表
-- 向test中插入元组
exec sql begin declare section;
const char *stmt="insert into test values(?)" -- 声明sql主变量内容是insert语句
exec sql end declare section;
...
exec sql prepare mystmt from:stmt; -- 准备语句,语句名是mystmt,其代表的就是insert into test
-- values(?)这条语句
...
exec sql execute mystmt using 100; -- 用100代替? ,所以语句变成了insert into test values(100)
exec sql execute mystmt using 200;
过程化sql是sql的扩展,增加了过程化语句功能,基本结构是块,每个块完成一个逻辑操作,块之间可以互相嵌套
过程化sql块的基本结构:
begin
sql语句定义,过程化sql的流程控制语句(for语句之类的)
exception
异常处理部分
end;
关系数据库管理系统查询处理分为:查询分析,查询检查,查询优化,查询执行.
事务:是用户定义的一个数据库操作系列,这些操作要么全做,要么全不做,是一个不可分割的工作单位,是恢复和并发控制的基本单位,事务是数据库的逻辑工作单位
事务和程序的区别:在关系数据库中,一个事务可以是一条或一组sql语句或者整个程序,一个程序通常包含多个事务
事务的定义:
-- 事务正常结束格式
begin transaction;
sql语句;
commit;
-- 事务异常终止格式
begin transaction;
sql语句;
rollback;
事务的特性:
数据库恢复的作用: 把数据库从错误状态恢复到某一个已知的正确状态,是数据库的最后一道防线,对系统的可靠程度起决定性的作用 ,恢复子系统的代码占整个系统的10%
故障的分类:
-- 银行转账事务,这个事务是把一笔金额从一个账户甲转给另一个账户乙
begin transaction
读账户甲的金额balance;
balance=balance-amount; --amount为转账金额
if(balance<0) then
{
打印'金额不足,不能转账'; -- 事务内部可能造成事务回滚的情况
rollback; -- 事务回滚,撤销已做的修改,数据库恢复的正确的状态,这就是可预期的错误
-- 但是事务内部更多的故障是非预期的,比如运算溢出,死锁等,一般我们说的故障,指的都是非预期故障
}
else
{
读账户乙的余额balance1;
banlance1=balance1+amount;
写会balance1;
commit;
}
恢复的实现技术:恢复机制涉及的关键问题是如何建立冗余数据,如何利用这些冗余数据实施数据库恢复
恢复策略
具有检查点的恢复技术
日志技术有两个问题:一个是搜索整个日志文件将耗费大量的时间,二是重做处理,重新执行,浪费了大量的时间,所以,我们提出了检查点技术以解决上述问题,在日志文件中增加检查点记录(该记录包含事务以及事务开始的地址),增加重新开始文件(该文件中记录了检查点记录的地址),恢复子系统在登陆文件期间动态的维护日志,注意,日志文件和重新开始文件是并列的,我们是在又日志文件的基础上,再创建一个重新开始文件,而不是再日志文件里创建重新开始文件
动态维护日志文件的方法:
数据库镜像(针对介质故障)