关系模型
关系模型的术语
-
关系模型:以二维表的形式来表示数据的相关特性以及数据之间的联系的一种数据结构
-
关系(表):关系模型中的每个二维表称为关系。关系是现实世界中的信息在数据库中的数据表示。表是含有数据库中所有数据的数据库对象
-
元组:表格中的一行,如学生表中的一个学生记录即为一个元组
-
属性:表格中的一列,相当于记录中的一个字段,如学生表中有五个属性(学号,姓名,性别,年龄,系别)
-
键码:可唯一标识元组的属性或属性集,如学生表中学号可以唯一确定一个学生,为学生关系的键码
-
域:属性的取值范围,通常通过属性的数据类型以及各种约束来实现。如学生表中年龄的域是(14~40),性别的域是(男、女)
-
分量:每一行对应的列的属性值,即元组中的一个属性值,如学号、姓名、年龄等均是一个分量
-
关系模式:对关系的描述,一般表示为: 关系名(属性1,属性2,……,属性n)
其中加下划线表示这两个属性的集合构成键码。如:学生(学号,姓名,性别,年龄)
在设计关系模型时,一般给出关系模式 -
实例:将给定关系中元组的集合称为该关系的实例。实例会随时间发生变化
扫描二维码关注公众号,回复: 13143647 查看本文章 -
当前实例:目前该关系中元组的集合
-
关系名称:学生基本信息,关系模式为:学生(学号,姓名,性别,年龄)
学号 | 姓名 | 性别 | 年龄 |
---|---|---|---|
197184013 | 张三 | 男 | 24 |
197184022 | 李四 | 女 | 25 |
100184013 | 王五 | 男 | 27 |
关系数据库
- 关系具有如下特性:
- 关系中不允许出现相同的元组
- 关系中元组的顺序(即行序)是无关紧要的,在一个关系中可以任意交换两行的次序
- 根据关系的这个性质,可以改变元组的顺序使其具有某种排序,可以提高查询速度
学号 | 姓名 | 生日 | 分数 |
---|---|---|---|
200101184022 | 王涛 | 1983/3/9 | 84 |
200201184358 | 于栋 | 1982/10/15 | 95 |
- 关系中属性的顺序是无关紧要的,即列的顺序可以任意交换。交换时,应连同属性名一起交换
- 同一属性名下的各个属性值必须来自同一个域,是同一类型的数据
- 关系中各个属性必须有不同的名字,不同的属性可来自同一个域
姓名 | 职业 | 兼职 |
---|---|---|
张强 | 教师 | 辅导员 |
王丽 | 工人 | 教师 |
刘宁 | 教师 | 辅导员 |
- 属性值可以为空值,表示“未知”或“不可使用”
- 关系中每一分量必须是不可分的数据项,或者说所有属性值都是原子的,即是一个确定的值,而不是值的集合
关系模型的优缺点
- 关系模型的优点
- 它有较强的数学理论根据(关系代数)
- 数据结构简单、清晰,用户易懂易用
- 关系模型的存取路径对用户透明,从而具有更高的数 据独立性、更好的安全保密性,也简化了程序员的工作和数据库建立和开发的工作
- 关系模型的缺点
- 由于存取路径对用户透明,查询效率往往不太好,因此,为了提高性能,必须对用户的查询表示进行优化, 增加了开发数据库管理系统的负担
从ODL到关系模型
属性的转换
- 首先,用与类名相同的名字建立一个关系名。
- ODL中的属性转换到关系模型时,需要根据数据类型来确定转换方式。
- 原子类型的属性:每个属性对应于关系的一个属性,关系的属性名和相应类的属性名相同。枚举类型实际上是前几个整数的别名列表。因此,枚举类型可以用整型的属性来表示。
- 非原子类型的属性需要区别对待。由于关系模型的属性要求具有原子类型,不能是聚集类型,因此对类中非原子类型的属性,必须经过转换才能对应关系中的属性。
非原子属性的转换
结构
结构的域本身都是原子类型,转换的方法:
- 将结构的每个域都转换成关系的一个属性。
- 如果两个结构有相同的域名,则必须在关系中使用新的属性名,以示区别。
例 考虑ODL模型
interface Star{
attribute string name;
attribute Struct Addr{string street,string city} address;}
转换成关系模式为Star(name,street,city)
集合
如果ODL中属性A是集合,则转换到关系模型的表示方法是:
- 模型中的属性名称与ODL中一致,属性的数据类型也与ODL 中一致,只是ODL中的每个对象都会对应关系模型中的多个元组,元组的数量就是对应集合属性的取值数量。
- 使用这种方法由ODL转换成关系,如果除了属性A和键码外还有其他属性,则会产生冗余信息。
例 假设有ODL如下:
interface Star{
attribute string name;
attribute Set<Struct Addr{string street,string city}> address; attribute date birthdate;}
转换成关系模式为:Star(name,street,city,birthdate)
集合类型的转换举例
关系模式Star(name,street,city,birthdate),下图为该关系的一个实例:
显然,其中的出生日期重复出现,产生冗余。
包
由于包中允许出现相同的元素,不能简单地在一个关系中引入n个相同的元组,而要在关系模式中增加一个计数的属性count,用以表明每个元组中对应的属性是包的多少次成员。
例Bag<int>
,则转换到关系模式中变成两个属性,原属性和count(为int类型)。
列表
列表可以增加一个新属性position(位置)来表示,用来表明在列表中的位置。
例List<int>
,则转换到关系模式中变成两个属性:原属性和position(为int类型)。
数组
定长的数组可以用带有数组位置标志的属性表示。
例Array<Struct Addr{ string street,string city } ,2>
则转换到关系模式中变成street1,city1,street2,city2。
联系的转换
- 对单值联系,把该联系看成是一个属性,该属性由与之联系的类的键码属性或属性集合构成。转换成关系模型时,用与之联系的类中构成键码的属性集来代替这个单值联系作为关系的属性。
- 对多值联系,即当联系是某个类的聚集类型时,同样需要首先找出相关类的键码,然后与数据类型为集合的属性的处理方法一样,需要为每个值建立一个元组。这种方法带来了冗余。因为对应于集合的每个成员,该关系的其他属性都将它们的值重复一次。
多值联系的转换
- 假设类C转换成关系模式,那么对应的关系中的属性构成包括:
- 类C的所有属性
- 类C中所有单值联系对应的类的键码属性
- 类C的多值联系对应的类的键码属性
- 有时,一个类可能有多个多值联系。在这种情况下,表示类中的一个对象所需的元组数会爆炸性增长。
- 假设类C有k个多值联系R1,R2,…,Rk,类C的某特定对象O通过联系R1与n1个对象相联,通过R2与n2个对象相联,……。
- 那么在类C对应的关系中,共有n1╳n2╳…╳nk个元组对应于ODL中设计的对象O。
多值联系的转换举例
假设类C有一个单值属性X和两个多值联系R1和R2,这两个联系将类C分别与键码属性为Y和Z的两个类相联。
现在,考虑类C的一个对象c,假设对象c的属性集X的值为x, 并且c通过联系R1与键码值分别为y1,y2的两个对象相联, 通过R2与键码值分别为z1,z2,z3的三个对象相联。
于是,对象c在对应于类C的关系中需要用六个元组表示,也就是Y对应的键码与Z对应的键码的所有可能组合。
(x,y1,z1) (x,y1,z2) (x,y1,z3) (x,y2,z1)
(x,y2,z2) (x,y2,z3)
interface GuYuan{
attribute int guyuanID;
attribute string name;
attribute int age;
attribute string address;
relationship dep workIn
inverse dep::myworker;
relationship dep headOf
inverse dep::header;}
interface dep{ attribute string name;
relationship Set<GuYuan> myworker
inverse GuYuan::workIn;
relationship GuYuan header
inverse GuYuan::headOf;
relationship Set<shangP> forsale
inverse shangP::toDep;}
联系单向表示的选择原则
ODL中联系与反向联系转换到关系模式时,二者只需选择一个进行转换,另一个则舍弃。其原则是
- 如果是多对多或一对一的联系,两个类中任选一个进行该联系的转换都可以。
- 如果是多对一的联系,则选择包括“多”的联系的类,即该类中的多个对象对应于另一类的一个对象。这样做可以避免冗余。
联系的转换举例
interface GuYuan{
attribute int guyuanID;
attribute string name;
attribute int age;
attribute string address; relationship dep workIn
inverse dep::myworker;
relationship dep headOf
inverse dep::header;}
interface dep{ attribute string name;
relationship Set<GuYuan> myworker
inverse GuYuan::workIn;
relationship GuYuan header
inverse GuYuan::headOf;
relationship Set<shangP> forsale
inverse shangP::toDep;}
dep(name, guyuanID, guyuanID2, shangpID)
interface shangP{ attribute string name;
attribute float price;
attribute string modelID;
attribute string shangpID;
relationship dep toDep
inverse dep::forsale;
relationship Set<maker> madeby
inverse maker::producer; }
interface maker{ attribute string name;
attribute string address;
relationship Set<shangP> producer
inverse shangP::madeby;}
interface Movie (key (title,year)){
attribute string title;
attribute integer year;
attribute integer length;
attribute enum Film {color,blackAndWhite} filmType;
relationship Set<Star> stars
inverse Star::starredIn;
relationship Studio ownedBy
inverse Studio::owns;}
interface Studio(key name){ attribute string name;
attribute string address;
relationship Set<Movie> owns
inverse Movie::ownedBy;}
interface Star (key name){
attribute string name;
attribute Struct Addr {string street,string city} address;
relationship Set<Movie> starredIn
inverse Movie::stars;}
下面是Movie关系的一个实例
title | year | length | filmType | studioName | starName |
---|---|---|---|---|---|
Star Wars | 1977 | 124 | color | Fox | Carrie Fisher |
Star Wars | 1977 | 124 | color | Fox | Mark Hamill |
Star Wars | 1977 | 124 | color | Fox | Harrison Ford |
Mighty Ducks | 1991 | 104 | color | Disney | EmilioEstevez |
Wayne’s World | 1992 | 95 | color | Paramount | Dana Carvey |
Wayne’s World | 1992 | 95 | color | Paramount | Mike Meyers |
- 用Studio的键码来代替单值联系ownedBy
- 用Star的键码来代替多值联系stars
ODL子类到关系的转换
将ODL子类转换成关系模式应该遵循下面的原则:
- 为每个子类建立自己的关系。
- 这个关系应该包括子类自己定义的特性以及它从超类继承的全部特性。
子类到关系的转换举例
假设除了类Movie外,还有以下三个类,
interface Cartoon:Movie{relationship Set<Star> voices…;}
interface Murder:Movie{attribute string Weapon;}
interface Cartoon-Murder:Cartoon,Murder {}
将这四个类转换成关系,这四个关系的模式如下:
Movie(title,year,length,filmType,studioName,starName)
Cartoon(title,year,length,filmType,studioName,starName, voice)
Murder(title,year,length,filmType,studioName,starName, weapon)
Cartoon-Murder(title,year,length,filmType,studioName, starName,voice,weapon)
解决办法:如果在元组中允许使用NULL值,就可以用单个关系来表示类的分层结构,该关系拥有的属性对应于子类的分层结构中所有的特性, 包括子类的和超类的。如果不是这个对象的类所拥有的特性,则该元组对应的属性就取值为NULL。
用NULL值合并关系举例
直接从ODL转换到关系时,得到
Movie(title,year,length,filmType,studioName,starName)
Cartoon(title,year,length,filmType,studioName,starName,voice)
Murder(title,year,length,filmType,studioName,starName,weapon)
Cartoon-Murder(title,year,length,filmType,studioName, starName,voice,weapon)
利用NULL来合并,则得到一个关系,其模式为:
Movie(title,year,length, filmType, studioName,starName,voice,weapon)
这种方法使得我们可以在一个关系中查找来自分层结构中所有类的一个对象的所有信息。
由ODL导出的关系的键码
由ODL转换成关系时键码的处理:
- 在ODL中没有定义键码并且无法断定哪些属性可以作为键码时,必须在相应的关系中引入一个属性,代替该类对象中的对象标识。如果在ODL中定义了键码,则直接继续下一步。
- 转换后关系的键码需要考虑该类的联系的情况。
- 假设类C指向某个类D的联系R是一对一或者多对一,
C的键码依然是相应关系的键码。 - 假设类C指向类D的联系R是“多对多”的联系,则需要把D的键码加入到C的键码中,来组成关系的键码。如果类C有多个多对多联系,则所有这些多值联系所连接的类的键码都必须加入到转换后的关系C的键码中, 得到的结果才是C对应的关系的键码。
- 假设类C指向某个类D的联系R是一对一或者多对一,
键码的转换举例
interface Movie {attribute string title;
attribute integer year;
attribute integer length;
attribute enum Film { color, blackAndWhite } filmType;
relationship Set < Star > stars
inverse Star::starredIn; }
interface Star {attribute string name;
attribute Struct Addr { string street,string city } address;
relationship Set<Movie> starredIn
inverse Movie::stars;}
假设在ODL定义中,不能肯定Name是影星的键码,则在转换到关系时,可以建立一个属性“cert#”(证书号),以此作为Star 的键码,则对应的Star关系模式为
Star(cert#,name,street,city,title,year)
同时,由于Star和Movie间存在着多对多联系,则对应的Movie关系的模式为
Movie(title,year,length,filmType,cert#)
对于自身到自身的联系,转换后的关系需要为每一次自身联系提供一次键码(此时需要经过改名)。
interface Person (key name){
attribute string name;
relationship Person motherOf
inverse Person::childrenOfFemale;
relationship Person fatherOf
inverse Person::childrenOfMale;
relationship Set<Person> children
inverse Person::parentsOf;
relationship Set<Person> childrenOfFemale
inverse Person::motherOf;
relationship Set<Person> childrenOfMale
inverse Person::fatherOf;
relationship Set<Person> parentsOf
inverse Person::children;}
Person(name,nameofmother,nameoffather,nameofchildren)
ODL转换成关系模式1
interface Customer (key ssNo) {attribute string name;
attribute string addr;
attribute string phone;
attribute integer ssNo;
relationship Set<Account> ownsAccts
inverse Account::ownedBy;}
interface Account (key number) {attribute integer number;
attribute string type;
attribute real balance;
relationship Customer ownedBy
inverse Customer::ownsAccts;}
Customer(ssNo, name, address, phone)
Account(number, type, balance, ssNo)
ODL转换成关系模式2
interface Ship (key name) {attribute string name;
attribute integer displacement;
attribute string type;}
interface Gunship:Ship {attribute integer numberOfGuns;
attribute integer bore;}
interface Carrier:Ship {attribute integer deckLength;
attribute Set<string> airGroups;}
interface Submarine:Ship {attribute integer maxSafeDepth;}
interface BattleCarrier:Gunship,Carrier {}
Ship(name, displacement, type)
Gunship(name, displacement, type, numberOfGuns, bore)
Carrier(name, displacement, type, deckLength, airGroups)
Submarine(name, displacement, type, maxSafeDepth)
BattleCarrier(name, displacement, type, numberOfGuns, bore,deckLength, airGroups)
allship(name, displacement, type, numberOfGuns, bore,deckLength, airGroup , maxSafeDepth)