数据库系统是一些相互关联的数据以及一组使得用户可以访问和修改这些数据的程序的集合。数据库系统的一个主要的目的是给用户提供数据的抽象视图, 也就是说,系统隐藏关于数据存储和维护的某些细节。
数据抽象
为了高效地检索数据在数据库系统中设计使用复杂的数据结构来表示数据,并简化用户与系统的交互,将其分为几个层次:
1. 物理层
最低层次的抽象,描述数据实际上是怎么存储的,屋里层详细描述复杂的底层数据结构
2. 逻辑层
比物理层稍高的抽象,描述数据中存储什么数据及这些数据间的关系。虽然逻辑层的简单结构的实现可能涉及复杂的物理层结构,但逻辑层的用户不必知道这样的复杂性。这被称作物理数据独立性 。
3. 视图层
最高层次的抽象,值描述整个数据库的某个部分。
关系图如下:
实例与模式
特定时刻存储在数据库中的信息的集合称作数据库的一个实例(instance)。而数据库的总体设计称作数据库模式。数据库模式即是发生变化,也不频繁。
根据之前讨论的不同的抽象层次,数据库系统可以分为几种不同的模式。
数据模型
数据库结构的基础是数据模型(data model) 。数据模型是一个描述数据、数据联系、数据语义以及一致性约束的概念工具的集合。数据模型提供了一种描述物理层、逻辑层及视图层数据库设计的方式
数据库系统提供数据定义语言 来定义数据库模式,以及数据操纵语言来表达数据库的查询和更新。
数据操纵语言
数据操纵语言(DML),它使得用户可以访问或操纵那些按照某种适当的数据模型组织起来的数据。有以下访问类型:
通常有两种基本的数据操纵语言:
数据定义语言
数据库模式是一系列定义来说明的,这些定义有一种称作数据定义语言(DDL)的特殊语言来表达。DDL也可用于定义数据的其他特征。
存储在数据库中的数据值必须满足某些一致性约束 :
关系数据库基于关系模型,使用一系列表来表达数据以及这些数据直接的联系。关系数据库也包括DML和DDL。
数据库系统被设计用来管理大量的信息。这些大量的信息并不是孤立存在的,而是企业行为的一部分;企业的终端产品可以是从数据库中得到的信息,或者是某种设备或服务,数据库对它们起到支持的作用。
数据库设计的主要内容是数据库模式的设计。
存储管理器
存储管理器是数据库系统中负责在数据库中存储的低层数据与应用程序以及向系统提交的查询之间的提供接口的部件。存储管理器负责与文件管理器进行交互。原始数据通过操作系统提供的文件系统存储在磁盘上。存储管理器将各种DML语言翻译成底层文件系统命令。因此、存储管理器负责数据库中数据的存储、检索和更新。
存储管理部件包括:
1. 权限及完整性管理器
它检测是否满足完整性约束,并检查试图访问数据的用户的权限
2. 事务管理器
它保证即使发生了故障,数据库也保持在一致的(正确的)状态,并保证并发事务的执行不发生冲突
3. 文件管理器
它管理磁盘存储空间的分配,管理用于表示磁盘上所存储信息的数据结构
4. 缓冲区管理器
它负责将数据从磁盘取到内存区,并决定哪些数据被缓冲存储到内存中。缓冲区管理器是数据库系统的一个关键部分,因为它使数据库可以处理比内存更大的数据
5. 数据文件
存储数据库本身
6. 数据字典
存储关于数据库结构的元数据,尤其是数据库模式
7. 索引
提供对数据项的快速访问
查询处理器
查询处理器组件包括:
事务是数据库应用中完成单一逻辑功能的操作集合。每一个事务是一个即具原子性又具一致性的单元。
原子性和持久性的保证是数据库系统自身的职责,确切的说,是恢复管理器的职责。
数据库系统各个部分以及它们之间联系的图,如下:
系统体系结构图。
数据挖掘这个术语指半自动化地分析大型数据库并从中找出有用的模式的过程。和人工智能中的知识发现(也称为机器学习)或者统计分析一样,数据挖掘视图从数据中寻找规律或模式。
数据库系统的一些应用领域受到关系型数据库模型的限制。其结果是,研究人员开发了几种数据模型来处理这些领域的应用,包括基于对象的数据模型和半结构化数据模型
数据库系统的一个主要目标是从数据库中检索信息和往数据库中存储新信息。使用数据库的人员可以分为数据库用户和数据库管理员
--------------------------------- 关系数据库 ------------------------------------------
关系数据库由表(table) 的集合构成,每个表有唯一的名字。
一般来说,表中一行代表了一组值之间的一种联系。由于一个表就是这种联系的一个集合,表这个概念和数学上的关系这个概念是密切相关的, 这也正是关系数据模型名称的由来。
在关系模型术语中,关系用来指代表,而元组用来指代行,属性用来指代表中的列
当我们谈论数据库时,我们必须区分数据库模型和数据库实例,前者是数据库的设计逻辑,后者是给定时刻数据库中数据的一种快照
关系的概念对应于程序设计语言中变量的概念,而关系模式的概念对应于程序设计语言中类型定义的概念
关系模式由属性序列及各属性对应域组成。关系实例的概念对应于程序设计语言中变量的值的概念
一个元组的属性值必须是能够唯一区分元组的。
超码是一个或者多个属性的集合,这些属性的组合可以使我们在一个关系中唯一地标识一个元组。
主码代表被数据库设计者选中的、主要用来在一个关系中区分不同分组的候选码。
外码,一个关系模式可能在它的属性中包括另一个关系模式的主码,这个属性就被称作外码。
一个含有主码和外码依赖关系的数据库模式可以用模式图来表示。
大学组织的模式图。每一个关系用一个矩形表示,关系的名字显示在矩形上方,矩形内列出各属性。主码属性用下划线标注。外码依赖用从参照关系的外码属性到被参照关系的主码属性直接的箭头来表示:
查询语言是用户用来从数据库中请求获取信息的语言。
查询语言分为过程化的和非过程化的。在过程化语言中,用户指导系统对数据库执行一系列操作以计算出所需结果。在非过程化语言中,用户只需要描述所需信息,而不用给出获取该信息的具体过程
所有的过程化关系查询语言都提供一组运算,这些运算要么施加于单个关系上,要么施加于一对关系上。这些运算具有一个很好的,并且也是所需要的性质:运算结果总是单个的关系。
---------------------------------------------------- SQL --------------------------------------------------------
SQL语言有以下几个部分:
数据库中的关系集合必须由数据定义语言DDL指定给系统。SQL的DDL不仅能够定义一组关系,还能够定义每个关系的信息,包括:
基本类型
SQL标准支持多种固定类型,包括:
* char(n):固定长度的字符串,用户指定长度n。也可以使用全称 character
* varchar(n):可变长度的字符串,用户指定最大长度n,等价于全称 character varying
* int:整数类型(和机器相关的整数的有限子集),等价于全称integer
* smallint:小整数类型(和机器相关的整数类型的子集)
* numeric(p,d):定点数,精度由用户指定。这个数有p位数字(加上一个符号位),其中d位数字在小数点右边。所以在一个这种类型的字段上,**numeric(3,1)**可以精确存储44.5,但不能精确存储444.5或0.32这样的数
* real、double precision:浮点数与双精度浮点数,精度与机器相关
* float(n):精度至少为n位的浮点数
基本模式定义
我们用create table命令定义SQL关系。下面的命令在数据库中创建了一个department关系:
create table department
(dept_name varchar(20),
building varchar(15),
budget numeric(12,2),
primary key(dept_name));
上面创建的关系具有三个属性,dept_name 是最大长度为20的字符串building是最大长度为15的字符串,budget是一个12位的数字,其中2位数字在小数点后面。create table命令还声明了dept_name属性是department关系的主码
SQL支持许多不同的完整性约束,这里介绍几个:
除Create table之外,还有insert命令将数据加载到关系中。delete命令从关系中删除元组。
SQL查询的基本结构由三个字句组成:select、from 和 where。查询的输入是在from字句中列出的关系,在这些关系中进行where和select字句中指定的运算,然后产生一个关系作为结果。
select name from instructor
其结果是由属性名name的单个属性构成的关系。如果instructor关系
如果查询结果有重复,可以在select后面加入关键字distinct
select distinct dept_name from instructor
上述查询结果,每种属性最多只出现一次。
where字句允许我们只选出哪些在from字句的结果关系中满足特定谓词的元组。
select name from instructor
where dept_name = 'Comp' and salary>70000
select name ,instructor.dept_name,building
from instructor,department
where instructor.dept_name = department.dept_name
两个关系联合查询
select name,course_id
from instructor,teaches
where instructor.ID = teaches.ID
该查询可以用SQL的自然连接运算更简洁地写作:
select name,course_id
from instructor natural join teaches
自然连接运算的结果是关系(表)。from字句中的 “ instructor natural join teaches ” 表达式可以替换成执行该自然连接后所得到的关系。然后在该关系的基础上执行where和select字句。
在一个SQL查询的from字句中,可以用自然连接将多个关系结合在一起,如下所示:
select A1,A2、A3,…,A4
fromr1 natural join r2 natural join … natural join rm
where P;
为了发扬自然连接的优点,同时避免不必要的相等属性带来的危险,SQL提供了一种自然连接的构造形式,允许用户来指定需要哪些列相等。
select name,title
from (instructor natural join teaches)join course using(course_id)
join…using运算中需要给定一个属性名列表,其两个输入中都必须具有指定名称的属性。
更名运算
SQL提供了一个重命名结果关系中属性的方法,即使用如下形式的as字句:
table1 as t1
as 字句即可出现在select字句中,也可出现在from字句中
例如:如果我们想用名字instructor_name 替代属性名name,哦们可以重新上述查询:
select name as instructor_name ,course_id
from instructor,teaches
where instructor.ID = teaches.ID
as子句在重命名关系时特别有用。重命名关系的一个原因就是把一个的关系名替换成短的,这样在查询的其他地方使用起来就更为方便。
select T.name,S.course_id
from instructor as T,teaches as S
where T.ID = S.DI
重命名关系的另一个原因是为了适用于需要比较同一关系中的元组的情况。如果同一关系比较,又不重命名的话,去不可能把一个元组与其他元组区分开来。
select distinct T.name
from instructor as T,teaches as S
where T.salary > S.salary and S.dept_name = 'Biology'
字符串运算
SQL使用一对单引号来表示字符串例如 ‘Computer。如果单引号是字符串的组成部分,那就用两个单引号字符来表示,如字符串 " it’s right" 可以表示为 " it’'s right"
在SQL标准中,字符串上的相等运算是大小写敏感的,所以表达式 “‘comp.sci.’ = ‘Comp.Sci’”的结果是假。
SQL还允许在字符串上有多种函数,例如串联(使用“||”)、提取子串、计算字符串长度、大小写转换(用upper(s) 的字符串s转换为大写或者用lower(s) 将字符串s转换为小写)、去掉字符串后面的空格(使用trim(s)),等等。
在字符串上使用like操作符来实现模式匹配。我们使用两个特殊字符来描述模式:
考虑查询“找出所在建筑名称中包含子串 ‘Watson‘ 的所有名称”,该查询的写法如下:
select dept_name
from department
where building like '%Watson%'
为使模式中能够包含特殊模式的字符(即 % 和 _),SQL允许定义转义字符
# 匹配所有以 ab%cd开头的字符串
select * from table where name like 'ab\%cd%' escape '\'
# 匹配所有以 ab\cd开头的字符串
select * from table where name like 'ab\\cd%' escape '\'
select 子句中的属性说明
星号’*'可以用在 select 子句中表示 “所有的属性”,因而,如下查询的 selelct 子句中使用 intructor.*
select instructor.*
from instructor,teaches
where instructor.ID = teaches.ID
表示instructor中的所有属性都被选中。
排列元组的显示次序
SQL为用户提供了一些对关系中元组显示次序的控制。 order by 子句就可以让查询结果排序。
order by默认使用升序。我们可以用 desc表示降序,** asc** 表示升序。
select *
from instructor
order by salary desc,name asc;
where 子句谓词
为了简化where子句,SQL提供了between 比较运算符了说明一个值是小于或等于某个值,同时大于或等于 另一个值的。
select name
from instructor
where salary between 90000 and 100000;
它可以取代
select name
from instructor
where salary <= 100000 and salary >= 90000;
类似的,我们也可以使用 not between 比较运算符
SQL的作用在关系上的 union、intersect 和 except运算对应数学集合论中的 ∩、∪ 和 - 运算。我们来构造包含这三种运算的查询。
(select id
from table1
where name = 'fail' and year = 2009)
union
(select id
from table2
where name = 'spring' and year = 2010);
与select子句不同,union 运算自动去除重复。如果我们想保留重复,就必须用union all 代替 union :(select id
from table1
where name = 'fail' and year = 2009)
union all
(select id
from table2
where name = 'spring' and year = 2010);
(select *
from table1
where name = 'fail' and year = 2009)
intersect
(select *
from table2
where name = 'spring' and year = 2010);
如果需要保留所有重复,就必须用intersect all 代替intersect(select * from table1 where name = 'fail' and year = 2009)
intersect all
(select * from table2 where name = 'spring' and year = 2010);
(select * from table1 where name = 'fail' and year = 2009)
except
(select * from table2 where name = 'spring' and year = 2010);
如果保留所有重复,必须用 except all代替except(select * from table where name = 'fail' and year = 2009)
except all
(select * from table where name = 'spring' and year = 2010);
空值给关系运算带来了特殊的问题,包括算数运算、比较运算和集合运算
如果算数运算的任一输入值为空,则该算数表达式结果为空。
聚集函数 是以值的一个集合(集或多重集)为输入、返回单个值的函数。SQL提供了五个固有聚集函数:
平均值:avg
最小值:min
最大值:max
总和:sum
计数:count
sum和 avg 的输入必须是数字集,但其它运算符还可作用在非数字数据类型的集合上,如字符串
基本聚集
计算教师的平均工资:
select avg(salary) as avg_salary
from instructor
where dept_name = 'Comp.Sci.';
计算平均值的时候,不能去重复。不然计算结果有误。
但是在某些情况下,如 计数 ,就必须要去重复,不然会重复计数,去重复的关键词是distinct ,以下是统计教授某一门科目的教师总数
select count(distinct ID)
from teaches
where semester = 'Spring' and year = 2010;
我们经常使用聚集函数count 计算一个关系中的元组的个数。SQL中该函数的写法是count(*) ,因此,要找出course关系中的元组数,可写成:
select count(*) from course
注意:SQL不允许在用count(*)时,使用distinct。在用max和 min时使用时合法的,尽管结果并无差别。
分组聚集
有时候我们不仅希望将聚集函数作用在单个元组上,而且也希望将其作用在一组元组集上;在SQL中可用group by子句实现这个愿望。group by子句中给出的一个或者多个属性是用来构造分组的。
在group by 子句中的所有属性上取值相同的元组将被分在一个组中。
select dept_name ,avg(salary) as avg_salary
from instructor
group by dept_name
注意:使用group by语句时,任何出现在select子句中,但没有被聚集的属性必须出现在group by中,否则查询被当做是错误的。
having 子句
有时候,对分组限定条件比对元组限定条件更有用。例如,我们只对教师平均工资超过42000 美元的系感兴趣。该条件并不针对单个元祖,而是针对group by子句构成的分组。为表达这样的查询,我们使用having子句。having子句中的谓词在形成分组后才起作用:
select dept_name,avg(salary) as avg_salary
from instructor
group by dept_name
having by (salary)>42000;
与select子句情况类型,任何出现在having子句中,但没有被聚集的属性必须出现在group by子句中,否则查询就被当做是错误的。
包含聚集、group by或having子句的查询的含义可通过下述操作序列来定义:
对空值和布尔值的聚集
聚集函数根据以下原则处理空值:除了count(*) 外所有的聚集函数都忽略输出集合中的空值。由于空值被忽略,有可能造成参加函数运算的输入值集合为空值。规定空集的count运算为0,其他聚集运算在输入为空集的情况下返回一个空值。
SQL提供嵌套子查询机制。子查询是嵌套在另一个查询中的select-from-where表达式。子查询嵌套在where子句中,通常用于对集合的成员资格、集合的比较以及集合的基数进行检查。
集合成员资格
SQL允许测试元组在关系中的成员资格。连接词 in 测试元组是否是集合中的成员,集合是由 select 子句产生的一组值构成的。连接词 not in 则测试元组是否不是集合中的成员。
select distinct course_id
from section
where semester = 'Fall' and year = 2009 and
course_id in
(select course_id from section where semester ='Spring' and year = 2010);
集合的比较
比如查询“找出满足某些条件的所有教师的姓名,他们的工资至少比中文系某一教师的工资要高”
一般写法:
select name from instructor as T,instructor as S
where T.salary > S.salary and S.dept_name = '中文系'
但SQL提供了另一种方式书写上面的查询。短语“至少比某一个要大”在SQL中用 > some 表示。所以我们可以重写上面的查询:
select name from instructor
where salary > some
(select salary from instructor where dept_name = '中文系');
子查询查出了中文系所有教师工资值的集合。当元组的salary值至少比中文系教师的所有工资值集合中某一成员高时,外层select 的where 子句中的 > some 的比较为真。
SQL还允许 < some , <= some, >= some, **= some **和 <> some 的比较。
空关系测试
SQL还有一个特性可检测一个子查询的结果中是否存在元组。 exists 结构在作为参数的子查询非空时返回true值。
select id from table as T
where name = 'Fall' and year = 2009 and
exists(
select * from table as B
where name = 'Spring' and year = 2010 and T.id = B.id);
上述查询还说明了一个SQL特性,来自外层查询的一个相关名称(上述中的T)可以用在where 子句中的查询中。使用了来自外层查询相关名称的子查询被称为相关子查询
重复元组存在性测试
SQL提供了一个布尔函数,用于测试在一个子查询的结果中是否存在重复元组。如果作为参数的子查询结果中没有重复的元组。那么unique结果将返回true值。我们可以用unique结构书写查询 “找出所有在2009年最多开设次的课程”:
select T.id
from course as T
where unique(
select R.id
from section as R
where T.id= R.id and R.year = 2009);
from子句中的子查询
SQL允许在from子句中使用子查询表达式。在此采用的主要观点是:任何 select-from-where 表达式的结果都是关系,因而可以被插入到另一个select-from-where 中任何关系可以出现的位置。例如“找出系平均工资超过42000美元的那些系中教师的平均工资”:
select dept_name,avg_salary
from (select dept_name ,avg(salary) as avg_salary
from instructor
group by dept_name)
where avg_salary > 42000);
with 子句
with子句提供定义临时关系的方法,这个定义只对包含with 子句的查询有效。考虑下面的查询,它找出具有最大预算值的系。
with max_budget(value) as
(select max(budget)
from deptment)
select budget
from department,max_budget
where department.budget = max_budget.value;
with子句定义了临时关系max_ budget ,此关系在随后的查询中马上就被使用了