前言
我想在进行数据库设计之前,需要要明白为什么设计数据库,不进行数据库设计可以吗?如果只是随便在院子里搭一个棚子需不需要先画图设计,但是如果要建造一栋大厦又需不需要设计?
思考之后,可以得出结论:面对复杂的数据库时,我们需要进行数据库设计。
概念
在数据库项目开发中,一个良好设计的数据库无疑有很多的好处。有较少的数据冗余、节省存储空间,能够保证数据的完整性。那么如何设计一个数据库,又有哪些流程。
按照软件开发的流程:
各阶段得到的文件:
实现
这里通过设计学生使用的机房收费系统的数据库来演示:
需求分析
分析用户的业务和数据处理需求,这一阶段,我们得到数据字典和数据流图
数据流图(Data Flow Diagram,DFD):通过数据流图来表达系统内数据处理的过程。
下面以收费系统的用户登录过程为例,来说明数据流图如何描述数据处理过程。
上图描述了用户登录系统的过程。用户在登陆界面输入用户名和密码进行登陆验证。通过查询用户信息文件来核对用户的身份,如果身份验证通过则创建一条登陆记录添加到登陆记录文件中,完成登陆登记。
数据字典和数据流图配合,能更清楚的表达数据处理的要求。用词条的方式定义在数据流图中出现的所有被命名的图形元素,包含数据流、加工、数据文件、数据元素以及数据源和数据谭。
下面是一个简单的示例:
- 数据元素条目(数据处理中最小、不可分割的单位)
- 数据流条目(数据结构在系统的传播路径)
- 数据存储文件条目(数据保存的地方)
- 加工条目(对数据流的处理)
- 数据源及数据谭条目(即外部实体)
概要设计
在概要阶段,我们要进行数据建模,即传统的实体-关系方法,它使用了三种互相关联的信息:数据实体、描述实体的属性、描述实体间相互连接的关系,使用E-R图来表述。
-
数据实体
在E-R图中,实体用矩形来表示,是具有若干属性信息的组合体。数据实体可以是外部实体(如显示器)、事物(如报表)、角色(如学生)、行为(如打电话)或者事件(如单击)、组织单位(如院系)、地点(如教室)、或结构(如文件)。
-
属性
属性定义数据实体的特征,在E-R图中用椭圆形来表示。
-
关系
各个实体之间的关系通过菱形来表示,它们之间的关联有三种:一对一(1:1)、一对多(1:m)、多对多(n:m)。
在这里为了避免属性太多而显得太乱,我去掉了实体的属性,仅展示实体和它们之间的联系。
详细设计
在详细设计中,需要把概要设计得到的E-R图转换为关系模式,并且进行范式检查
原则:
- 一个实体转换为一个关系模式,实体的属性就是关系的属性,实体的键就是关系的键;
- 联系在转换为关系模式时,分为以下三种不同的情况:
- 若联系为1:1,可以在两个实体类型转换成的两个关系模式中任意一个关系模式的属性中加入另一个关系模式的键和联系类型的属性。
- 若联系为1:n,则在N端实体类型转换成的关系模式中加入1端实体类型的键和联系类型的属性。
- 若联系为m:n,则将联系类型也转换成关系模式,其属性为两端实体类型的键加上联系类型的属性,而键为两端实体键的组合。
范式检查
- 第一范式:每列都不可分割,在关系型数据库中,第一范式满足
- 第二范式:不出现局部依赖
- 第三范式:不出现传递依赖
最后的关系模式为下面所示:
用户(账号,密码,姓名,性别,类型,操作人)
T_User (userID,userPWD,userName,userSex,userType,signOperator)
登陆(账号,登陆时间,注销时间,机器名称)
T_UserLogin (userID,loginDateTime,logoutDateTime,loginComputer)
系统(临时费率,固定费率,至少上机时间,准备时间,至少充值金额,计费单位,修改人)
T_System (tempRate,rate,leastTime,preprareTime,limitRechargCash,unitTime,systemModifier)
学生(学号,姓名,性别,班级,年级,学院,系部,专业,注册人,注册时间)
T_Student (stuNo,stuName,stuSex,class,grade,academy,department,major,register,registerDateTime)
卡(卡号,金额,类型,使用状态,售卡人,注册时间)
T_Card (cardID,cash,type,status,register,registerDateTime)
充值(卡号,充值金额,充值人,充值时间,是否结账)
T_CardRecharge (cardID,cash,rechargeOperator,rechargeDateTime,isCheck)
退卡(卡号,退卡金额,退卡人,退卡时间,是否结账)
T_CardCancel (cardID,cash,cancelOperator,cancelDateTime,isCheck)
学生绑定卡(学号,卡号,绑定人,绑定时间,绑定状态)
T_Binding (stuNo,cardID,bindOperator,bindDateTime,isBind)
上机(卡号,上机时间,下机时间,消费时间,消费金额,上机机器)
T_OnLine (cardID,onLineDateTime,offLineDateTime,costTime,costCash,computer)
账单(充值金额,退还金额,剩余金额,结账时间,结账人)
T_Bill (rechargeCash,cancelCash,remainCash,checkDateTime,checkOperator)
实现
这里使用了PowerDesigner来实现数据库
SQL文件为:
/*==============================================================*/
/* Database name: JFCharge */
/* DBMS name: Microsoft SQL Server 2008 */
/* Created on: 2016/3/10 9:54:07 */
/*==============================================================*/
use JFCharge
go
if exists (select
from sys.sysreferences r join sys.sysobjects o on (o.id = r.constid and o.type = 'F')
where r.fkeyid = object_id('T_Binding') and o.name = 'FK_T_BINDIN_REFERENCE_T_CARD')
alter table T_Binding
drop constraint FK_T_BINDIN_REFERENCE_T_CARD
go
if exists (select
from sys.sysreferences r join sys.sysobjects o on (o.id = r.constid and o.type = 'F')
where r.fkeyid = object_id('T_Binding') and o.name = 'FK_T_BINDIN_REFERENCE_T_STUDEN')
alter table T_Binding
drop constraint FK_T_BINDIN_REFERENCE_T_STUDEN
go
if exists (select
from sysobjects
where id = object_id('T_Bill')
and type = 'U')
drop table T_Bill
go
if exists (select
from sysobjects
where id = object_id('T_Binding')
and type = 'U')
drop table T_Binding
go
if exists (select
from sysobjects
where id = object_id('T_Card')
and type = 'U')
drop table T_Card
go
if exists (select
from sysobjects
where id = object_id('T_CardCancel')
and type = 'U')
drop table T_CardCancel
go
if exists (select
from sysobjects
where id = object_id('T_CardRecharge')
and type = 'U')
drop table T_CardRecharge
go
if exists (select
from sysobjects
where id = object_id('T_OnLine')
and type = 'U')
drop table T_OnLine
go
if exists (select
from sysobjects
where id = object_id('T_Student')
and type = 'U')
drop table T_Student
go
if exists (select
from sysobjects
where id = object_id('T_System')
and type = 'U')
drop table T_System
go
if exists (select
from sysobjects
where id = object_id('T_User')
and type = 'U')
drop table T_User
go
if exists (select
from sysobjects
where id = object_id('T_UserLogin')
and type = 'U')
drop table T_UserLogin
go
/*==============================================================*/
/* Table: T_Bill */
/*==============================================================*/
create table T_Bill (
rechargeCash decimal(,) null,
cancelCash decimal(,) null,
remainCash decimal(,) null,
checkDateTime datetime null,
operator varchar() null
)
go
/*==============================================================*/
/* Table: T_Binding */
/*==============================================================*/
create table T_Binding (
stuNo varchar() not null,
cardID varchar() not null,
operator varchar() not null,
bindDateTime datetime not null,
isBind char() not null,
constraint PK_T_BINDING primary key (stuNo, cardID)
)
go
/*==============================================================*/
/* Table: T_Card */
/*==============================================================*/
create table T_Card (
cardID varchar() not null,
cash decimal(,) not null,
type char() not null,
status char() not null,
register varchar() not null,
registerDateTime datetime not null,
constraint PK_T_CARD primary key (cardID)
)
go
/*==============================================================*/
/* Table: T_CardCancel */
/*==============================================================*/
create table T_CardCancel (
cardID varchar() not null,
cash decimal(,) not null,
operator varchar() not null,
cancelDateTime datetime not null,
isCheck char() not null
)
go
/*==============================================================*/
/* Table: T_CardRecharge */
/*==============================================================*/
create table T_CardRecharge (
cardID varchar() not null,
cash decimal(,) not null,
operator varchar() not null,
rechargeDateTime datetime not null,
isCheck char() not null
)
go
/*==============================================================*/
/* Table: T_OnLine */
/*==============================================================*/
create table T_OnLine (
cardID varchar() not null,
onLineDateTime datetime not null,
offLineDateTime datetime null,
costTime datetime null,
costCash decimal(,) null,
computer varchar() not null
)
go
/*==============================================================*/
/* Table: T_Student */
/*==============================================================*/
create table T_Student (
stuNo varchar() not null,
stuName varchar() not null,
stuSex char() not null,
class varchar() not null,
grade varchar() not null,
academy varchar() not null,
department varchar() not null,
major varchar() not null,
register varchar() not null,
registerDateTime datetime not null,
constraint PK_T_STUDENT primary key (stuNo)
)
go
/*==============================================================*/
/* Table: T_System */
/*==============================================================*/
create table T_System (
tempRate decimal(,) not null,
rate decimal(,) not null,
leastTime int not null,
preprareTime int not null,
limitRechargeCash decimal(,) not null,
unitTime int not null,
systemModifier varchar() not null
)
go
/*==============================================================*/
/* Table: T_User */
/*==============================================================*/
create table T_User (
userID varchar() not null,
userPWD varchar() not null,
userName varchar() not null,
userSex char() not null,
userType char() not null,
operator varchar() not null,
constraint PK_T_USER primary key (userID)
)
go
if exists (select from sys.extended_properties
where major_id = object_id('T_User') and minor_id = )
begin
declare @CurrentUser sysname
select @CurrentUser = user_name()
execute sp_dropextendedproperty 'MS_Description',
'user', @CurrentUser, 'table', 'T_User'
end
select @CurrentUser = user_name()
execute sp_addextendedproperty 'MS_Description',
'用户表',
'user', @CurrentUser, 'table', 'T_User'
go
/*==============================================================*/
/* Table: T_UserLogin */
/*==============================================================*/
create table T_UserLogin (
userID varchar() not null,
loginDateTime datetime not null,
logoutDateTime datetime null,
loginComputer varchar() not null
)
go
alter table T_Binding
add constraint FK_T_BINDIN_REFERENCE_T_CARD foreign key (cardID)
references T_Card (cardID)
go
alter table T_Binding
add constraint FK_T_BINDIN_REFERENCE_T_STUDEN foreign key (stuNo)
references T_Student (stuNo)
go
小结
其实我们在设计数据库时,如果只是按照标准的流程和规则来完成工作,那么很可能感觉无从下手,我们可以先通过自己的一些生活经验来完成初步的数据库设计。
比如说,分析机房收费系统在确定实体的时候,我们平时的生活经验就是这个系统应该要有学生、上机卡(需要注册、充值)、操作员(给我们办理上下机)、系统等实体,先初步确定之后再仔细分析。还有范式检查的时候还有更高的范式,但是我们一般在设计的时候使其满足第三范式就可以了。
以上就是数据库设计的大致流程,以机房收费系统为例子,这当中可能由于博主理解的偏差,会有不合适的地方,希望大家可以指出来,共同进步。