一、数据库设计
一、数据库结构设计三范式
**第一范式:**是对属性的原子性,要求属性具有原子性,不可再分解。
如有如下表结构设计:
create table Student --学生表 ( StuId varchar(20) primary key,--学号 StuName varchar(20) not null,--学生姓名 StuContact varchar(50) not null, --联系方式 ) insert into Student(StuId,StuName,StuContact) values('001','刘备','QQ:185699887;Tel:13885874587') select * from Student
上述设计则不满足第一范式,联系方式这一列并不是不可再分的最小单元,应修改为如下结构
create table Student --学生表 ( StuId varchar(20) primary key,--学号 StuName varchar(20) not null,--学生姓名 Tel varchar(20) not null, --联系电话 QQ varchar(20) not null, --联系QQ )
**第二范式:**是对记录的惟一性,要求记录有惟一标识,即实体的惟一性,即不存在部分依赖;
如有如下表结构设计:
--选课成绩表 create table StudentCourse ( StuId varchar(20),--学号 StuName varchar(20) not null,--学生姓名 CourseId varchar(20) not null,--课程编号 CourseName varchar(20) not null, --选课课程名称 CourseScore int not null, --考试成绩 ) insert into StudentCourse(StuId,StuName,CourseId,CourseName,CourseScore) values('001','刘备','001','语文',80) insert into StudentCourse(StuId,StuName,CourseId,CourseName,CourseScore) values('001','刘备','002','数学',70) insert into StudentCourse(StuId,StuName,CourseId,CourseName,CourseScore) values('002','关羽','003','英语',80) insert into StudentCourse(StuId,StuName,CourseId,CourseName,CourseScore) values('003','张飞','003','英语',90)
上述设计中有两个事物,一个学生信息,一个课程信息,很显然这两个事物都没有保证实体的唯一性,这里的姓名依赖学号,课程名称依赖课程编号,所以不符合二范式。
create table Course --课程 ( CourseId int primary key identity(1,1),--课程编号 CourseName varchar(30) not null, --课程名称 CourseContent text --课程介绍 ) insert into Course(CourseName,CourseContent) values('HTML','静态网页的制作') insert into Course(CourseName,CourseContent) values('WinForm','Windows应用程序开发') create table Student --学生 ( StuId int primary key identity(1,1), --学生编号 StuName varchar(50) not null, --学生名字 StuSex char(2) not null --学生性别 ) insert into Student(StuName,StuSex) values('刘备','男') insert into Student(StuName,StuSex) values('关羽','男') create Table Exam --考试信息表 ( ExamId int primary key identity(1,1), --选课成绩编号 StuId int not null, --学生编号 CourseId int not null, --课程编号 Score int not null, --考试分数 ) insert into Exam(StuId,CourseId,Score) values(1,1,90) insert into Exam(StuId,CourseId,Score) values(1,2,80) insert into Exam(StuId,CourseId,Score) values(2,2,85) select * from Student inner join Exam on Student.StuId = Exam.StuId inner join Course on Course.CourseId = Exam.CourseId
**第三范式:**要求任何字段不能由其他字段派生出来,它要求字段没有冗余,即不存在传递依赖 ;
如有如下表结构设计:
create table Student ( StuId varchar(20) primary key,--学号 StuName varchar(20) not null,--学生姓名 ProfessionalId int not null,--专业编号 ProfessionalName varchar(50),--专业名称 ProfessionalRemark varchar(200), --专业介绍 ) insert into Student(StuId,StuName,ProfessionalId,ProfessionalName,ProfessionalRemark) values('001','刘备',1,'计算机','最牛的专业') insert into Student(StuId,StuName,ProfessionalId,ProfessionalName,ProfessionalRemark) values('002','关羽',2,'工商管理','管理学的基础专业') insert into Student(StuId,StuName,ProfessionalId,ProfessionalName,ProfessionalRemark) values('003','张飞',1,'计算机','最牛的专业') select * from Student
上述设计种专业名称字段和专业介绍字段,在数据库种会产生很多冗余数据,不满足第二范式,优化方案如下:
create table Professional ( ProfessionalId int primary key identity(1,1),--专业编号 ProfessionalName varchar(50),--专业名称 ProfessionalRemark varchar(200), --专业介绍 ) create table Student ( StuId varchar(20) primary key,--学号 StuName varchar(20) not null,--学生姓名 ProfessionalId int not null,--专业编号 ) insert into Professional(ProfessionalName,ProfessionalRemark) values('计算机','最牛的专业') insert into Professional(ProfessionalName,ProfessionalRemark) values('工商管理','管理学的基础专业') insert into Student(StuId,StuName,ProfessionalId) values('001','刘备',1) insert into Student(StuId,StuName,ProfessionalId) values('002','关羽',2) insert into Student(StuId,StuName,ProfessionalId) values('003','张飞',1) select * from Student
二、表关系
(1)一对多关系(专业--学生)
create table Profession --专业 ( ProId int primary key identity(1,1), --专业编号 ProName varchar(50) not null --专业名称 ) create table Student --学生 ( StuId int primary key identity(1,1), --学生编号 ProId int references Profession(ProId), StuName varchar(50) not null, --学生名字 StuSex char(2) not null --学生性别 ) insert into Profession(ProName) values('软件开发') insert into Profession(ProName) values('企业信息化') insert into Student(ProId,StuName,StuSex) values(1,'刘备','男') insert into Student(ProId,StuName,StuSex) values(1,'关羽','男') insert into Student(ProId,StuName,StuSex) values(2,'张飞','男') insert into Student(ProId,StuName,StuSex) values(2,'赵云','男') select * from Student left join Profession on Student.ProId = Profession.ProId
(2)一对一关系(学生基本信息--学生详情)
方案一:
create table StudentBasicInfo --学生基本信息 ( StuNo varchar(20) primary key not null, --学号 StuName varchar(20) not null, --姓名 StuSex nvarchar(1) not null --性别 ) create table StudentDetailInfo --学生详细信息 ( StuNo varchar(20) primary key not null, StuQQ varchar(20), --QQ stuPhone varchar(20), --电话 StuMail varchar(100), --邮箱 StuBirth date --生日 ) --插入数据的时候按照顺序先插入刘备的基本信息,在插入关羽的基本信息 --insert into StudentBasicInfo(StuNo,StuName,StuSex) values('QH001','刘备','男') --insert into StudentBasicInfo(StuNo,StuName,StuSex) values('QH002','关羽','男') --插入数据的时候按照顺序先插入关羽的详细信息,在插入刘备的详细信息 --insert into StudentDetailInfo(StuNo,StuQQ,stuPhone,StuMail,StuBirth) --values('QH002','156545214','13654525478','guanyu@163.com','1996-6-6') --insert into StudentDetailInfo(StuNo,StuQQ,stuPhone,StuMail,StuBirth) --values('QH001','186587854','15326545214','liubei@163.com','1998-8-8') --或者如下结构也行: create table StudentBasicInfo --学生基本信息 ( StuNo int primary key identity(1,1), --学号 StuName varchar(20) not null, --姓名 StuSex nvarchar(1) not null --性别 ) create table StudentDetailInfo --学生详细信息 ( StuNo int primary key, --学号 StuQQ varchar(20), --QQ stuPhone varchar(20), --电话 StuMail varchar(100), --邮箱 StuBirth date --生日 )
此方案要求两个表的主键相等关系确定一个学生,所以此设计必须保证主键是可以维护和编辑的,如果主键是自动增长,将很大程度增加了数据维护的难度。
方案二:
create table StudentBasicInfo --学生基本信息 ( StuNo int primary key identity(1,1), --学号 StuName varchar(20) not null, --姓名 StuSex nvarchar(1) not null --性别 ) create table StudentDetailInfo --学生详细信息 ( StuDetailNo int primary key identity(1,1), --详细信息编号 StuNo int references StudentBasicInfo(StuNo) --学号,外键 StuQQ varchar(20), --QQ stuPhone varchar(20), --电话 StuMail varchar(100), --邮箱 StuBirth date --生日 )
此方案中实际上我们是使用一对多的模式来表示一对一,保证多的表中只有一条对应数据即可。
(3)多对多关系:(选课成绩--学生)
create table Course --课程 ( CourseId int primary key identity(1,1),--课程编号 CourseName varchar(30) not null, --课程名称 CourseContent text --课程介绍 ) insert into Course(CourseName,CourseContent) values('HTML','静态网页的制作') insert into Course(CourseName,CourseContent) values('WinForm','Windows应用程序开发') create table Student --学生 ( StuId int primary key identity(1,1), --学生编号 StuName varchar(50) not null, --学生名字 StuSex char(2) not null --学生性别 ) insert into Student(StuName,StuSex) values('刘备','男') insert into Student(StuName,StuSex) values('关羽','男') create Table Exam --考试信息表 ( ExamId int primary key identity(1,1), --选课成绩编号 StuId int not null, --学生编号 CourseId int not null, --课程编号 Score int not null, --考试分数 ) insert into Exam(StuId,CourseId,Score) values(1,1,90) insert into Exam(StuId,CourseId,Score) values(1,2,80) insert into Exam(StuId,CourseId,Score) values(2,2,85) select * from Student inner join Exam on Student.StuId = Exam.StuId inner join Course on Course.CourseId = Exam.CourseId
此方案中,一个学生可以有多门选课,一门课程也可以被多个学生选择,我们称之为多对多关系,在处理多对多关系的时候,我们需要建立一个中间关联表,该关联表中需要有另外两张表的主键字段。
三、数据库设计案例
业务需求说明: 模拟银行业务,设计简易版的银行数据库表结构,要求可以完成以下基本功能需求: 1.银行开户(注册个人信息)及开卡(办理银行卡)(一个人可以办理多张银行卡,但是最多只能办理3张) 2.存钱 3.查询余额 4.取钱 5.转账 6.查看交易记录 7.账户挂失 8.账户注销
表设计:
1.账户信息表:存储个人信息。 2.银行卡表:存储银行卡信息。 3.交易信息表(存储存钱和取钱的记录) 4.转账信息表(存储转账信息记录) 5.状态信息变化表(存储银行卡状态变化的记录,状态有1:正常,2:挂失,3:冻结,4:注销)
表结构设计:
--账户信息表:存储个人信息 create table AccountInfo ( AccountId int primary key identity(1,1), --账户编号 AccountCode varchar(20) not null, --身份证号码 AccountPhone varchar(20) not null, --电话号码 RealName varchar(20) not null, --真实姓名 OpenTime smalldatetime not null, --开户时间 ) --银行卡表:存储银行卡信息 create table BankCard ( CardNo varchar(30) primary key, --银行卡卡号 AccountId int not null, --账户编号(与账户信息表形成主外键关系) CardPwd varchar(30) not null, --银行卡密码 CardMoney money not null, --银行卡余额 CardState int not null,--1:正常,2:挂失,3:冻结,4:注销 CardTime smalldatetime default(getdate()) --开卡时间 ) --交易信息表(存储存钱和取钱的记录) create table CardExchange ( ExchangeId int primary key identity(1,1), --交易自动编号 CardNo varchar(30) not null, --银行卡号(与银行卡表形成主外键关系) MoneyInBank money not null, --存钱金额 MoneyOutBank money not null, --取钱金额 ExchangeTime smalldatetime not null, --交易时间 ) --转账信息表(存储转账信息记录) create table CardTransfer ( TransferId int primary key identity(1,1),--转账自动编号 CardNoOut varchar(30) not null, --转出银行卡号(与银行卡表形成主外键关系) CardNoIn varchar(30) not null, --转入银行卡号(与银行卡表形成主外键关系) TransferMoney money not null,--交易金额 TransferTime smalldatetime not null, --交易时间 ) --状态信息变化表(存储银行卡状态变化的记录,状态有1:正常,2:挂失,3:冻结,4:注销) create table CardStateChange ( StateId int primary key identity(1,1),--状态信息自动编号 CardNo varchar(30) not null, --银行卡号(与银行卡表形成主外键关系) OldState int not null, --银行卡原始状态 NewState int not null, --银行卡新状态 StateWhy varchar(200) not null, --状态变化原因 StateTime smalldatetime not null, --记录产生时间 )
添加测试数据:
--为刘备,关羽,张飞三个人进行开户开卡的操作 --刘备身份证:420107198905064135 --关羽身份证:420107199507104133 --张飞身份证:420107199602034138 insert into AccountInfo(AccountCode,AccountPhone,RealName,OpenTime) values('420107198905064135','13554785425','刘备',GETDATE()) insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState) values('6225125478544587',1,'123456',0,1) insert into AccountInfo(AccountCode,AccountPhone,RealName,OpenTime) values('420107199507104133','13454788854','关羽',GETDATE()) insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState) values('6225547858741263',2,'123456',0,1) insert into AccountInfo(AccountCode,AccountPhone,RealName,OpenTime) values('420107199602034138','13456896321','张飞',GETDATE()) insert into BankCard(CardNo,AccountId,CardPwd,CardMoney,CardState) values('6225547854125656',3,'123456',0,1) select * from AccountInfo select * from BankCard --进行存钱操作,刘备存钱2000元,关羽存钱:8000元,张飞存钱:500000元 select * from AccountInfo update BankCard set CardMoney = CardMoney + 2000 where CardNo = '6225125478544587' insert into CardExchange(CardNo,MoneyInBank,MoneyOutBank,ExchangeTime) values('6225125478544587',2000,0,GETDATE()) update BankCard set CardMoney = CardMoney + 8000 where CardNo = '6225547858741263' insert into CardExchange(CardNo,MoneyInBank,MoneyOutBank,ExchangeTime) values('6225547858741263',8000,0,GETDATE()) update BankCard set CardMoney = CardMoney + 500000 where CardNo = '6225547854125656' insert into CardExchange(CardNo,MoneyInBank,MoneyOutBank,ExchangeTime) values('6225547854125656',500000,0,GETDATE()) --转账:刘备给张飞转账1000元 update BankCard set CardMoney = CardMoney -1000 where CardNo = '6225125478544587' update BankCard set CardMoney = CardMoney + 1000 where CardNo = '6225547854125656' insert into CardTransfer(CardNoOut,CardNoIn,TransferMoney,TransferTime) values('6225125478544587','6225547854125656',1000,GETDATE())
- 员工管理系统之RBAC权限管理数据库设计
- 设计模式- 使用抽象工厂实现多数据库切换实现过程
- 数据库设计问题
- 【游戏数据库】大型网络游戏数据库设计方面讨论?(微软平台) 游戏数据库
- 数据库设计的那些事儿!~(第一篇)
- 公交车路线查询系统后台数据库设计--查询算法
- 58同城数据库架构设计思路
- 数据库—单例设计,基本操作
- 数据库设计范式(From Exceed PHP)
- 数据库设计的5种常见关系
- 数据库设计中,动态添加字段
- 效率大提高:数据库设计的14个技巧
- PowerDesigner在数据库设计中的使用
- 数据库设计:表的设计命名的十个注意点
- 数据库学习:高并发数据库设计
- 数据库设计三大范式应用实例剖析
- 软件工程 - 5、数据库设计与开发
- 假如让你来设计数据库中间件
- 数据库设计三大范式应用实例剖析
- 大型数据库的设计原则与开发技巧