您的位置:首页 > 数据库

数据库基础小结

2011-07-17 22:01 281 查看
一. 由数据库到关系型数据库

数据库是一个相关联数据的集合,同时实际应用到的数据库应该具有下面说到的三条隐含的性质:1)数据库表示真实世界的某些方面(微观世界),并且微观世界的变化必须及时在数据库中有所反映。2)数据库中的数据需在逻辑上保存一致,并具有某些内存的含义。3)数据库的设计,创建和数据库的必须与实际用户的需求相吻合,或者满足特定目的需要。

如何构建一个现代数据库?这就好比建一座现代化大厦,同是高楼,但写字楼,办公楼和酒店确是各有各的不同,他们外表相似其不同体现在内部结构模型上。因此在构建一个满足特定目的的数据库之前也得为其构建一个数据模型,而最终呈现给用户的仍然是以一个数据库文件的形式。数据模型(data model)是一个可用于描述数据库结构的概念集合,它提供了为获得数据抽象所必需的工具。数据库结构通常理解为包括数据类型,数据间的联系和施加在数据上的一些约束,此外大多数数据模型还包括一个对数据了进行检索和更新的基本操作的集合。

现在问题的关键在于如何为数据库建立数据模型?目前一种流行的高级概念数据库模型为—实体-联系模型(Entity-Relationship model,ER模型)。ER模型中用实体,联系和属性的概念来描述数据,这很好理解。ER模型中的实体代表的是现实世界中独立存在的“事物”,既可以是物理存在的对象,也可以只是概念存在的对象,如一个项目,一门课程等。事物的属性即为实体的属性,它用来描述实体的某些特定性质。例如雇员这个实体就包含了姓名,年龄,地址,工资等属性。这些属性一般来说都有属性值,即使某个实体的某个属性没有值,那么它的值也就为NULL。由实体,属性的概念我们可以进一步引出实体类型,实体集,码和值集的定义。实体类型定义为一个具有相同属性的实体的汇集或集合。而在任意时刻数据库内某个特定类型的所有实体集合称为实体集。一个实体类型通常具有这样一个属性,其属性值对于实体集中每个单独的实体都是不同的,这样的属性称为码属性,如一个工厂中所有工人的工号即为码属性,因为它惟一的标识了该公司中的这个雇员。实体类型的每个简单属性都与一个值集或值域相联系,所谓的值集就是指每个单独实体的属性可能具有的值的集合。已知上面这些概念我们已经可以建立起一个实体类型内部实体的数据模型,而实际上各个实体类型与实体类型之间也存在着某种隐含的联系,可以说只要类型的某个属性参照另外的实体类型,它们之间就存在着某种联系,下面要建立的是这种联系的表示。

在实体类型的初步设计中,通常以属性的形式来表现联系,随着设计的改进,这样的属性被转换为实体类型间的联系。N个实体类型E1,E2,E3…EN间的联系类型R在这些类型的实体之间定义了一个关联的集合,或者说联系集。这有点类似于实体类型与实体集,联系类型同样可以具有属性,例如雇员(EMPLOYEE)类型与部门类型(DEPARTMENT)之间存在WORKS_ON这个联系类型,我们可以为这个类型指定属性Start_time以说明该雇员在该部门开始工作的时期。此外,联系类型还具有约束,联系类型上的约束限制了参与到相应联系集的那些实体的可能组合,这些约束来自联系所表示的微观世界。

无论是ER模型还是增强型的EER模型都只是数据库设计过程中的概念数据模型,要上升到实际可操作的数据模型需要经过映射算法的转换。在数据库发展的前几十年里,数据以各种不同的方式存储并展现给用户。例如在层次数据库系统中,以一个或多个树形结构来表示数据。而在网状数据库系统中,它表现为多个记录集合,集合之间通过外国投资来定义不同记录间的关系。层次和网关数据库仍然存在,尽管主要在大型机领域。在20世纪70年代由于IBM研究院E.F.Codd博士的贡献,一种新的表示数据的方式逐步扎根并获得发展,这种方式更为严谨,且易于理解和实现,这就是鼎鼎大名的关系数据库。

关系数据模型和关系数据库

关系模型把数据库表示成关系的集合,何为关系?它类似于一张记录表,也可说是一张值表。表中每一行为一个相关数据值的集合,例如在学生(STUDENT)这个关系中,每行是一个学生姓名,性别,年龄,家庭地址等数据的集合。标记这些值的名称为称为属性,也就是关系模型中的列标题,行称为元组,而表理所当然就是叫关系了。我们不会仅仅用一张表来表示要建立的数据库,这样既低效又无组织。所以往往一个数据库是多个关系的集合,各表并不是孤立的,表与表之间通过冗余数据建立联系,冗余数据也是表中某一个或多个属性,我们称之为外键,一个关系表可通过外键导航到其它表信息。到此我们可以用下面这段文字来粗略地引出并概括关系模式:关系模式(relation schema)R,用R(A1,A2,A3…An)表示,它由关系名R和属性列表A1,A2,A3…An组成。每个属性Ai是一个角色名,这个角色由关系模式R中的某个域D扮演。

上述表述着重在单个关系的特征,在一个数据库中,通常会有多个关系,而且这些关系中的元组往往以多种形式进行关联,并且对于关系中的数据和关系间的关联必然会存在某种约束,而不是随意的,这些约束源自于数据库所表示的微观世界的规则。这些约束大体上我们可以归为如下几类:

1).数据模型中的固有的约束,也称为因有的基于模型的约束,或者隐式约束。如关系中元组的排序,元组中的值和NULL等。

2).在数据模型的模式中直接表示的约束,通常用数据定义语言(DDL)加以指定,我们称这种约束为基于模式的约束或显示约束。如域约束,它指定每个元组中的每个属性A的值必须是来自域dom(A)的原子值。又如码约束和NULL值约束,码约束规定一个关系中没有两个元组可以在它们的所有属性上具有相同的值的组合。必定存在一个属性子集使得在关系模式R的任何一个状态r中的两个元组在该属性子集上值的组合都不相同。如果这种子集表示为SK,那么对于R的一个关系状态r中任何两个不同的元组t1和t2,存在约束:t1[SK] != t2[SK].属性上的另一个约束是是否允许使用NULL值,例如STUDENT关系中的学生姓名就必须有一个有效的非空的值,那么该属性就应该具有NOT NULL约束。

3).不能在数据模型的模式中直接表示的约束,因此必须由应用程序表示和执行。我们称这种约束为基于应用的约束或者称为语义约束或者业务规则。

4).实体完整性约束:规定主码值不能为NULL

5).参照完整性约束:码约束和实体完整性约束都是在单个关系上指定的,而参照完整性约束则是在两个关系之间指定的,用于维持两个关系的元组之间的一致性。通俗地说,参照完整性约束规定的是一个关系中的元组参照另一个关系时,它参照的必须是那个关系中已存在的元组。

三. 关系型数据库系统中的查询(SQL)

数据库建立好以后有必要提供高效的查询和数据更新机制,也即为数据库提供一种接口以操控关系表中的数据。结构化查询语言(SQL)历经数十年版本更新,已被公认为现代商业关系DBMS的标准接口。

SQL是一种综合性的数据库语言,它包含数据定义,查询和更新语句。因此,SQL既是一种数据定义语言(DDL)也是一种数据操作语言(DML)。与我们常用的如Java,C#,C/C++不同,SQL是一种非过程化语句,它只定义必要的输入和输出,而执行语句的方式则交由数据库引擎的一个组件,即优化器(optimizer)来处理。以下通过一个实例来实际说明简单的SQL.

//code by chuigeqiu

/***********************************************************************

//-->U1

CREATE TABLE EMPLOYEE

(

Fname VARCHAR(15) NOT NULL,

Lname VARCHAR(15) NOT NULL,

Ssn CHAR(9) NOT NULL,

Bdate DATE

Dno INT NOT NULL,

PRIMARY KEY(Ssn),

FOREIGN KEY(Super_ssn) REFERENCES EMPLOYEE(Ssn),

FOREIGN KEY(Dno) REFERENCES DEPARTMENT(Dnumber)

);

//-->U2

CREATE TABLE DEPARTMENT

(

Dname VARCHAR(15) NOT NULL,

Dnumber INT NOT NULL,

Mgr_ssn CHAR(9) NOT NULL,

Mgr_start_date DATE,

PRIMARY KEY(Dnumber),

UNIQUE(Dname),

FOREIGN KEY(Mgr_ssn) REFERENCES EMPLOYEE(Ssn)

);

************************************************************************/

1).CREATE TABLE命令用于定义一个新的关系,并为这个关系赋予名称,指定它的属性和约束。U1中雇员EMPLOYEE即为表名称,如Fname,Lname,Ssn者为属性。SQL中的属性含多种数据类型,如数值型(如INTERGER,INT,SMALLINT,FLOAT,REAL,DECIMAL(ij)),字符串型(如CHAR(n)或VARCHAR(n),前者为定长n的字符串,后者为变长n的字符串),布尔型(由SQL中,由于空值NULL的存在,使用了一个三值逻辑,所以布尔型除了传统的TRUE,FALSE外还有UNKNOWN),日期型(date)和时间型(time)等。U1中如Fname,Lname,Dno者我们为其指定了实体完整性约束NOT NULL.此外就关系EMPLOYEE而言还可以在CREATE TABLE命令中指定码和参照完整性约束,U1中通过PRIMARY KEY(…)命令,指定了Dnumber为主码,UNIQUE(…)指定了Dname为辅码即候选码。FOREIGN KEY(…) REFERENCES table(…)字句由为关键,因为它指定了一个参照完整性约束,意为关系EMPLOYEE中的属性Dno参数照了关系DEPARTMENT中的属性Dnumber.这样一来Dno即被当作了一个外码。那什么叫做外码呢?成为外码的条件就是要在两个关系模式R1和R2之间规定一个参照完整性约束,如下面所述。如果关系模式R1中的属性集FK满足下面的两条规则,那么FK就是R1中对于参照关系R2的外码。

(1)FK中的属性具有与R2的主码PK中的属性相同的域。在这种情况下,称FK参照或引用了关系R2.

(2)当前状态r1(R1)的元组t1中的FK值,或者作为当前状态r2(R2)的某个元组t2中的PK值而存在,或者为NULL。在前一种情况下,有t1[FK]=t2[fk],并且称元组t1参照或引用了元组t2。

2).基本查询的SELECT-FROM-WHERE结构:

SELECT <属性列表>:是一个属性名的列表,通过这个查询来检索它们的值

FROM <关系列表>:是一个处理该查询所需要的关系列表名

WHERE <条件表达式>:是一个条件(布尔)表达式,它识别被查询检索的元组

3).SQL中的插入,删除和更新语句

INSERT命令:形式最简单的INSERT命令用于在关系中增加单个元组。必须在INSERT中指定关系名和元组值的列表,值的排列顺序应该与CREATE TABLE命令中指定的属性顺序一致(这也说明关系表中的属性是有顺序的,但元组可以是无序的)。此外,如果我们仅需要对其中一个或某几个属性赋值,同样可以显示地指定属性名,但所列属性中必须包含声明为NOT NULL和无默认值的全部k属性,而那些允许NULL值或有DEFAULT值的属n性是可以不考虑的。

DELETE命令:从关系中删除元组,它包括一个与SQL查询中的用法相似的WHERE子句,用来选择要被删除的元组。DELETE命令一次只能显式地删除一个表中的元组。但是,如果在DDL的参照完整性中指定了参照触发动作,那么一个关系中元组的删除就可能会影响到其他关系中的元组。一个DELETE命令删除的元组个数可能为0个,1个或多个,这信赖于WHERE子句中的条件所选择的元组个数。

DELETE FROM table //关系名

WHERE …; //条件

UPDATE命令:用来修改一个或者多个被选中的元组的属性值。就像DELETE命令那样,UPDATE命令中的WHERE子句从单个关系中选择要修改的元组。但是,如果在DDL的参照完整性约束中定义了一个参照触发动作,那么更新一个主码的值就可能会影响到其他关系中元组的外码值。另外,一个SET子句用于指定要被修改的属性和它们的新值。

UPDATE table //关系名

SET … //指定要被修改的属性和他们的新值

WHERE … //条件

一个单一的UPDATE命令可以修改多个元组,也可以指定NULL或者DEFAULT作为新的属性值。需要注意的是,每个UPDATE命令只能显式地指定一个关系。如果要修改多个关系,就必须执行多个UPDATE命令。

四. 应用中的SQLITE3小型嵌入式关系型数据库

软件设计开发中通常都是用一种通用程序设计语言,如Java,C/C++等。而SQL是一种非过程化的语言,因此单独使用SQL并不能开发完整的应用,除了编写简单的脚本处理某些数据。一般需要将SQL与编程语言相集成。已经有多种技术在应用程序中包括数据库交互的存在。目前一些主要的数据库程序设计方法有:1)将数据库命令嵌入到通用程序设计语言中。2)使用数据库函数库。宿主程序设计语言通过使用函数库来实现数据库调用,这种方法提供了从应用程序访问数据库的一种众所周知的应用编程接口(Appliation Programming Interface,API).3)设计一种全新语言(不常用)。

在WFS客房端项目中我们以小型嵌入式数据库sqlite3来保存用户的备份任务以及用户配置信息。Sqlite3提供了一个函数库也就是API接口供程序员灵活地操控数据库文件.

SQLite3.0一共有83个API函数,此外还有一些数据结构和预定义。但是我们常的简单操作只需要三个函数就可以完成:

sqlite3_open16( const void *filename,sqlite **ppDb)

(注:根据字符编码方式的不同,数据库打开函数有4种版本,这里引用的是以UTF-16编程字符的版本)

sqlite3_exec( sqlite3*,

const char *sql,

int (*callback)(void*,int,char**,char**),

void*,

char **errmsg );

sqlite3_close(sqlite3 *);

要是想更好的控制数据库引擎的执行,可以使用提供的sqlite3_prepare(…)函数把SQL语句编译成字节码,然后在使用sqlite3_step(…)函数来执行编译后的字节码,以sqlite3_finalize(…)做清理工作。这三个函数原型如下,其详细说明见sqlite3.h。

int sqlite3_prepare16(

sqlite3 *db, /* Database handle */

const void *zSql, /* SQL statement, UTF-16 encoded */

int nByte, /* Maximum length of zSql in bytes. */

sqlite3_stmt **ppStmt, /* OUT: Statement handle */

const void **pzTail /* OUT: Pointer to unused portion of zSql */

int sqlite3_step(sqlite3_stmt*);

int sqlite3_finalize(sqlite3_stmt *pStmt);

在我们的WFS项目中,定义了一个DBExec类,其成员函数封装了一些将要用到的一些对数据库的操作。此外还定义了一个DBSQL类,其成员函数专门用来打包特定SQL命令,并以Cstring类型返回,返回的字符串给DBExec类成员函数作参数,如此灵活,方便地对数据库进行操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: