Lesson 8 Overview of Data Modeling and Database Design
第八章 数据建模和数据库设计的概述
软件开发的步骤可大致分为: ①需求分析 ②系统设计 ③编码实现 ④系统测试 ⑤运行维护
系统设计中一个重要的环节就是数据库设计。数据库设计的时候需要先进行数据建模(实体关系图 E-R图),而数据建模的依据就是前期所做的需求分析。
实体-关系图
实体-关系图(Entity Relationship Diagram):也称为E-R图,提供了表示实体类型、属性和关系的方法,用来描述现实世界的概念模型。
构成E-R图的基本要素是 实体、 属性和 关系
实体(Entity):实体用来表示具有相同特征和性质的事物(类似于java的类(域对象)),实体由实体名和实体属性来表示。 圆角矩形 表示实体(实体名大写,属性小写)
属性(Attribute):实体所具有的某一特性,一个实体可以有若干个属性
关系(Relationship):实体彼此之间相互连接的方式称为关系。一般可分为以下 3 种类型:
一对一关系 (1 ∶ 1) 这种关系比较少见
维护关系:外键放在任意一方例如:丈夫和妻子
丈夫 妻子
id name w_id id name
1 zhangsan 2 1 lisi
2 wangwu
一对多关系 (1 ∶ N) 比较常见:
维护关系:外键放在多的一方
比如:飞机和乘客
多对多关系 (M ∶ N) 维护关系:构建桥表,外键放在桥表中
student(学生) course(课程)
s_id sname id name
1 zhangsan 1 java
2 lisi 2 c++
student_course_brige(选课表)
s_id c_id id
1 1 1
1 2 2
2 1 3
2 2 4
ER图中符号的表示
1) #:主要标识,代表该属性是唯一的,有可能作为主键。
(#):次要标识
2) * : 代表该属性是非空的
#*:表示主键。
3) o : 可有可无,代表没有任何要求
4) 虚线: may be 顾客这边虚线,顾客可能没有订单
5) 实线: must be 订单这边实线,订单一定是属于某个客户。
6) 竖杠(|): UID Bar代表要强制在(|)一方建立一个联合主键,将对方ID拿过来做 联合主键。
7) 伞状图标代表多的一方,不是伞状图标则代表的是少的一方
简单来说:由两个或者两个以上的字段联合在一起作为主键,就称为联合主键。
student
c_id 学号 姓名 性别
1 1 张三 男
1 2 张三 女
2 1 张三 男
may-be 和 must-be
在实体与实体之间的关系中,都会存在着may-be和must-be这俩种情况,例如:
系统中有订单和顾客俩个实体(N:1关系),一个顾客对应多个订单,一个订单对应一个顾客,而且一个顾客可以(may be)没有订单和他对应,一个订单一定(must be)会有顾客和它对应.
数据库设计
数据建模完成之后,可以把ER图转换成数据中的表①实体的名字转换为表的名字
②实体的属性转换为表中的列
③具有唯一特点的属性设置为表中的主键
④根据实体之间的关系设置为表中某列为外键列(主外键关联)
设计关系数据库时,遵从不同的规范要求,才能设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,越高的范式数据库冗余越小。
目前关系数据库有 六种范式:
第一范式(1NF)
第二范式(2NF)
第三范式(3NF)
巴斯-科德范式(BCNF)
第四范式(4NF)
第五范式(5NF,又称完美范式)
注:满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。一般说来,数据库只需满足第三范式(3NF)就行了
第一范式(确保每列保持原子性):一个表中,每个列里面的值是不能再分割的.
例如:我们设计的表中有一个列是:爱好,这个列的值可能会是这样:足球篮球乒乓球,但是这值是可以再分割的:足球、篮球、乒乓球。所以这种设计是不满足第一范式
第二范式(确保表中的每列都和主键相关):
第二范式是在满足第一范式的基础上,表中的非主键列都必须依赖于主键列
例如:订单表中,订单编号是主键
订单编号 订单名称 订单日期 订单中产品的生产地
这几个非主键列中,产品生产地是不依赖于订单编号的,所以这种设计是不满足第二范式
第三范式(确保每列只和主键列直接相关,而不是间接相关):
第三范式是在满足第二范式的基础上,表中的非主键列都必须直接依赖于主键列,而不能间接的依赖.(不能产生依赖传递)
例如: 订单表: 订单编号是主键
订单编号 订单名称 顾客编号 顾客姓名
顾客编号依赖于订单编号,顾客姓名依赖于顾客编号。从而顾客姓名间接的依赖于订单编号,那么这里产生了依赖传递,所以这个设计是不满足第三范式的
主键和外键
主键:
①能做主键的列必要满足非空唯一的特点
②只要满足非空唯一的列都可以做主键
③可以让表中一个有意义的列做主键,比如说学号,它既表示学生学号又作为表中的主键,因为这个列满足非空唯一的条件
④也可以找一个没有意义的列做主键,就是用来唯一标识一行记录的
⑤我们可以让多个列联合在一起做表中的主键,那么它就是联合主键,要求这几个列的值联合在一起是非空唯一的
外键:
①表中的某一个列声明为外键列,一般这个外键列的值都会引用于另外一张表的主键列的值(有唯一约束的列就可以,不一定非要引用主键列)
②另外一张表的主键列中出现过的值都可以在外键列中使用
③外键列值也可以为空的,前提是这个外键列在表中不做主键,因为我们也可以把表中的外键列当做主键来使用(只有满足非空唯一的要求就可以)
④如果把B表中的联合主键的值引用到A表中做外键,因为是俩个列在B表中做联合主键,那么A表引用过来的时候也要把俩个列的值都引用过来,那么它们在A表中就会作为一个联合外键出现
------------------------------------------------------------------------------
Lesson 9 Create Table
①表结构 存储数据
②视图 一张表或多张表中数据的字节
③sequence 主要用来生成主键值
④index 提高检索性能
我们需要学会创建数据结构
2.表结构:
①表结构可以随意创建
②表结构不需要预先申请空间
③可以在线修改。
3.创建语法:
创建表的方式有两种:基本操作 子查询
3.1基本操作
3.1.1 语法:
create table [schema.]tb_name(
col_name datatype [default value] [colum_constraints],
...,
[table_constraint],
...
);
note :
①create table 关键字,固定写法,
schema,在oracle数据库中代表用户名,如果没有这个,就把该表创建在你登录时的用户下(高权限用户向低权限用户创建)
②tb_name代表表名,可以自定义:但是需要遵循命名规则(详见3.1.2命名规则):
③列名一般也要求遵循命名规则(详见3.1.2命名规则)
④dataType,列所属的数据类型,详见(3.1.3 oracle支持的数据类型)
3.1.2 命名规则(表名和字段名)
①字母开头
②长度为1-30
③只能有大小写英文(a-z),数字(0-9)和_ $ #
④同一个用户下的对象名不能重复
⑤不能使用关键词作为表名(如:select group等等)
3.1.3 oracle支持的数据类型:
类型名 描述
VARCHAR2(size) 可变长字符串
CHAR(size) 定长字符串
NUMBER 数字类型
NUMBER(p,s) 数字类型
DATE 日期类型
CLOB 字符大数据对象
BLOB 二进制大数据对象
note:
①char,varchar2,varchar
用法: char(size),varchar2(size) varchar(size) size用来指明所能保存字符值的上限。
区别:
char:定长字符,即一旦确定了()中的字符个数,在保存数据的时候,不论你保存的字符个数为多少个,所占空间大小为固定的()中的字符个数。如char(2): 保存 a ab都占用2个字符空间
varchar , varchar2: 不定长字符,即在保存数据的时候,会先判断字符个数,然后再分配对应的空间进行保存。
如varchar(2),保存a 占用1字符空间,保存ab 占用两2字符空间。
在oracle数据库中,指定变长字符串首选 varchar2.
② number(p,s) : p确定数字的有效位数,s确定数字的小数点位数
number(5,3)最大值和最小值为多少?
-99.999~99.999
③ date: 日期类型
系统默认日期类型:'DD-MON-YY'
操作字符类型和日期类型数据的时候,一定要放到''中间
3.1.4 default: 设置默认值
①作用:设置在往表中插入数据时,如果没有指定该列的值,默认插入的值。
②默认值可以是合法的字面值(根据定义的列的数据类型来赋值),表达式,或者是sysdate和user等合法的sql函数。
create table test(
start_date date default sysdate
);
③默认值不能使用其他表的列或者不存在的列/伪列
3.1.5 约束
定义:所谓约束就是强制表中的数据列必须遵循的一些规则。而且如果表中存在依赖约束,可以阻止一些不合理的删除操作。
分类:
表级约束:定义在表级别的约束(即在列的完整定义完成后,才定义的约束)
column dataType , unique(column)
列级约束:直接跟在列完整性定义后边的约束
column dataType unique,
种类:
约束名 描述 分类NOT NULL : 非空 列级
UNIQUE : 唯一 列级/表级
PRIMARY KEY : 主键 列级/表级
FOREIGN KEY : 外键 列级/表级
CHECK : 自定义(选择) 列级/表级
---->测试:
create table test(
id number(7),
name varchar2(10),
gender varchar2(10)
);
insert into test values(1,'tom','male');
创建语法:
列级约束/行级约束: ①在字段申明的时候就指定约束类 ②只作用某一个字段有效
create table 表名(
列名1 数据类型 列级约束,
列名2 数据类型 列级约束,
列名3 数据类型 列级约束,
列名4 数据类型 列级约束
);
表级约束:①在字段申明之后才指定约束类型 ②可以作用在表中的所有字段有效
create table 表名(
列名1 数据类型,
列名2 数据类型,
列名3 数据类型,
列名4 数据类型,
表级约束1,
表级约束2
);
建表实例
例如1:
//普通的建表例子
create table student(
id number primary key,
name varchar2(20) not null,
age number default 0
);
drop table student;
例如2:
//使用四种列级约束 主键约束 非空约束 唯一约束 check约束
create table student(
id number(7) primary key,
name varchar2(100) not null,
email varchar2(100) unique,
gender char(1) check(gender in('f','m')),
age number default 0
);
drop table student;
例如3:
//使用列级约束 声明 外键约束
create table t_customer(
id number primary key,
name varchar2(20) not null
);
create table t_order(
id number primary key,
content varchar2(200) not null,
customer_id number references t_customer(id)
);
drop table t_customer;
drop table t_order;
注意:订单表中的外键列customer_id的值,是引用自顾客表t_customer中的主键列id的值
①这时候直接删除顾客表是不行的,因为t_customer的主键列的值被别的表给引用了.
②我们可以先删除订单表t_order,然后再删除t_customer就可以了
③如果非要想直接删除到顾客表t_customer,就需要使用下面的语句:
drop table t_customer cascade constraints;
④该语句表示,删除t_customer表的同时,也级联删除与表相关的约束,外键约束没有了,这个表自然可以被删除掉
⑤cascade是级联的意思
例如4:
//使用表级约束
create table student(
id number,
name varchar2(20) not null,
age number default 0,
email varchar2(100),
gender char,
primary key(id),
unique(email),
check(gender in('f','m'))
);
drop table student;
注:非空约束(not null)不能声明成表级约束,因为它是列级约束
例如5:
//使用表级约束 声明 外键约束
create table t_customer(
id number primary key,
name varchar2(200) not null
);
create table t_order(
id number primary key,
content varchar2(200) not null,
customer_id number,
foreign key(customer_id) references t_customer(id)
);
drop table t_order;
drop table t_customer;
例如6:
//使用表级约束 声明 联合唯一约束
create table student(
id number primary key,
class varchar2(50) not null,
name varchar2(50) not null,
unique(class,name)
);
drop table student;
注意:学生的班级和学生的名字联合起来必须是唯一的(联合唯一)
注意:联合唯一约束必须使用表级约束来声明
例如7:
//使用表级约束 声明 联合主键
create table t_customer(
id number,
name varchar2(50),
primary key(id,name)
);
drop table t_customer;
例如8:
//使用表级约束 声明 联合外键
create table t_customer(
id number,
name varchar(50),
primary key(id,name)
);
create table t_order(
id number,
price number not null,
customer_id number,
customer_name varchar(50),
foreign key(customer_name,customer_id) references t_customer(name,id)
);
drop table t_order;
drop table t_customer;
表级约束和列级约束对比
①表级约束和列级约束所写的位置不一样
②not null约束不能用表级约束来声明
③表级约束和列级约束声明语法稍有所不同
④如果要声明的约束为联合主键、联合外键、联合唯一的时候,就一定要用表级约束.
constraint关键字
①constraint是约束的意思
②建表的时候可以给约束起一个名字,这个名字起的规律一般会是:表名_列名_约束类型
③如果没有给约束起名字,那么系统也会给这个约束起一个默认的名字,这不过这个默认的名字对我们来说并不友好(我们看不懂)
④将来我们可以根据我们之前给约束起好的名字而找到这个约束,然后进行修改
3.2. 子查询
一般使用子查询建表,要将另外一张表中的某些数据存放到一张新的表格中。(相当于将原来打印在控制台上的信息,现在直接定义成一张新的表格。)语法:
create table tb_name[(column,...)]
as
select ...
note:
①在用子查询建表时,只有not Null约束会被复制。(可以直接在表名后面的字段名中跟约束类型)
②创建表时可以指定列名,也可以不指定,但是一定不指定列的数据类型
③创建表的列跟子查询表的列数要保持一致。
测试---->create table stu(
id number(7) primary key,
name varchar2(20) not null,
phone char(11) unique,
age number(2) default 0,
gender char(2) check(gender in('0','1')),
c_id number(10) references s_dept(id) not null
);
查询约束名:
select constraint_name from user_constraints
where table_name='STU';
取约束名字:constraint 约束名 (位置:放在约束类型的前面)
约束名:表名_字段名_约束类型
pk fk nn uk ck
总结:
主键约束:primary key
①列级约束
字段 数据类型 取约束名 primary key,
②表级约束
字段 数据类型,
取约束名 primary key(字段),
3)联合主键
字段1 数据类型,
字段2 数据类型,
取约束名 primary key(字段1,字段2),
外键约束:foreign key
①列级约束
字段 数据类型 取约束名 references 表(字段),
②表级约束
字段 数据类型,
取约束名 foreign key(字段) references 表(字段),
③联合外键
字段1 数据类型,
字段2 数据类型,
取约束名 foreign key(字段1,字段2) references 表(字段1,字段2),
非空键:not null ①列级约束
选择性约束:check ①列级约束 ②表级约束
唯一键:unique
①列级约束
字段 数据类型 取约束名 unique 表(字段),
②表级约束
③联合唯一键--表级约束
name1 varchar2(20),
name2 varchar2(20),
取约束名 unique(name1,name2),
create table A(
id1 number;
id2 number;
primary key(id1,id2)
);
create table B(
a_id1 number,
a_id2 number,
foreign key(a_id1,a_id2) references A(id1,id2)
);
选择规则:
①非空约束只能列级约束
②联合主键,联合外键,联合唯一键只能表级约束
③其他的情况任意选择
----------------------------------------------------------------------
model 10 数据字典
1.字典,就是用来帮助人们查看一些信息,查看一些内容
2.数据字典描述:
①数据字典在数据库被创建时创建。
②被数据库服务器自动更新和维护
oracle的数据字典就是oracle存放有关数据库信息的地方。用途就是用来描述数据的。 比如一个表的创建者信息,创建时间信息,所属表空间信息,用户访问权限信息等。数据库数据字典是一组表和视图结构。它们存放在system表空间中,当用户在对数据库中的数据进行操作时遇到困难就可以访问数据字典来查看详细的信息。用户可以用SQL语句访问数据库数据字典。
例如:
1.查看当前用户可以访问的所有数据字典
select table_name from dictionary;
常见的数据字典(它们都是视图)
user开头的视图里面存放着用户自己拥有的对象
all开头的视图存放着用户有权限查看的对象
dba开头的视图存放着数据库所有的对象
V$开头的视图存放数据库运行的一些性能属性数据
根据查询的结果(按照前缀不同可以分为四类):
按前缀不同,作用范围的分为三类:
1、以user开头的数据字典: 包含当前用户所拥有的相关对象信息。--能够查到对象的所有者是当前用户的所有对象
user_tables;
user_views;
user_sequences;
user_constraints;
2、以all开头的数据字典: 包含当前用户有权限访问的所有对象的信息。
//查到当前用户有权限访问的对象
select table_name from all_tables;
3、以dba开头的数据字典: 包含数据库所有相关对象的信息。
//只能是有dba权限的用户查询,能查到数据库中所有对象
select table_name from dba_tables; (sys system)
4、以V$开头的是动态服务性能视图。
select table_name from dba_tables (sys system)
例如:
①查看当前用户的拥有的对象名和对象类型:
select object_name,object_type
from user_objects;
②查看当前用户下的所有的表
select table_name from user_tables; (user_tables就是一个数据字典)
③查看当前用户所定义的所有的约束的名字和类型
select constraint_name, constraint_type
from user_constraints
where table_name = 'STUDENT';
4.查找约束名字和关联的列的名字
select constraint_name, column_name
from user_cons_columns
where table_name = 'S_EMP';
-------------------------------------------------------------------------
Lesson 11 Manipulating Data (DML)
事务控制语言: commit rollback savepoint
1.insert语句
两种格式: ①直接插入 ②子查询插入
1. 直接插入基本语法:insert into tb_name[(col_name,...)] values(val1,....);
note:
①如果给每个列都插入数据,可以省略table后边的列,并且插入值的顺序和定义表的顺序一致
②如果插入的顺序和表定义的顺序不同,或者只插入某几列的值table_name后边必须跟上列名
③字符串和日期类型的值必须使用''引起来
④insert语句一次只插入一条数据
⑤插入的值可以使用系统函数,例如---user,sysdate
⑥插入的值可以使用运行时参数。
例如:
create table test(
id number primary key,
name varchar2(10),
gender varchar2(2) check (gender in ('F','M')),
birthday date
);
插入:①insert into test(id,name) values (3,'zs');
②insert into test(id,name,birthday) values(1,'lisi','09-9月-10');
③insert into test(id,name,birthday) values(2,user,sysdate);
④insert into test(id,name,birthday) values(&id,'ss',sysdate);
2.使用子查询插入insert into table_name[(col_name,....)]
select .......
note:
①不出现values关键字
②插入的列的名字和子查询返回结果的列相匹配。
例如:
① insert into test2
select * from test;
② insert into test2(id,gender,name,birthday)
select id,gender,name,birthday from test;
2. delete语句:语法:delete [from] tbl_name [where option...]
note:在加外键约束的时候,如果想在删除主表的记录的同时对外键表中已经存在的关联关系记录进行操作可以使用下面两个关键词:
on delete cascade:级联删除,删除主表记录,外键表的关联记录一块儿删除
on delete set null:删除主表记录,外键表的关联记录该列的值变成null
例如:
①从test2表中删除id = 1
delete from test2 where id = 1;
create table test2(id primary key) as select id from s_emp;
②create table test3(
id number references test2(id) on delete cascade);
create table test3(
id number references test2(id) on delete set null);
3. update 语句:
语法:update table_name set column=value,[column=value]
[where condition...];
note:如果不加条件,默认修改表中所有的行。
例如:
①update test set name = 'wangwu',gender='M'
where id = 3; 只更改id=3的行。
②update test set gender = 'F';所有行都改。
4. 事务控制:
当一个sql命令执行,一个事务就开始了,当遇到以下情况,事务自动完成
①commit或者rollback ②DDL或者DCL命令执行 ③错误,退出,或者系统崩溃
五种分类:针对sql命令
查询语句 select
数据操作语言:DML insert,update,delete
数据定义语言:DDL create,alter,drop,rename,truncate
事务控制语句:commit,rollback,savepoint
数据控制语言:DCL grant(授权),revoke(回收权限)
note:
commit:提交事务,提交事务是指让这个事务里面的所有操作都生效到数据库中
rollback:回滚事务,回滚事务是指让这个事务里面的所有操作都撤销
测试: 使用两个终端窗口,同一个账号登录到数据库中,观察事务是否提交对用户查看数据的影响
注:一个用户对A表某一列做了DML操作,但是没有提交事务,这时候别的用户是不能对A表这一列再做其他的DML操作。(为了保证数据的安全和一致性)
例如1:
insert ....产生事务A
update ... 这个操作是事务A中的操作
insert .. 这个操作是事务A中的操作
commit; 让事务A里面的三个操作生效、事务A结束
delete ... 产生新的事务B
insert .. 这个操作是事务B中的操作
insert .. 这个操作是事务B中的操作
insert .. 这个操作是事务B中的操作
rollback; 让事务B中的四个操作都撤销,事务B结束
例如2:
insert ....产生事务A
update ... 这个操作是事务A中的操作
insert .. 这个操作是事务A中的操作
DDL语句; 事务A会被提交
rollback; 这时候回滚已经对事务A不起作用,因为事务A以及被提交了
注:create语句 drop语句 alter语句等属于DDL语句
事务控制使用:commit,savepoint,rollback;
5.事务的ACID原则:
① 原子性:要不全成功,要不全失败② 一致性:从一个一致性状态到达另外一个一致性状态 ③ 持久性:事务提交后,能够持久性影响数据库。
④ 隔离性:事务之间互不影响
第一类丢失更新:事务A撤销事务时,将事务B已经提交的事务覆盖了。
第二类丢失更新:
事务A和事务B同时修改某行的值,①事务A将数值改为1并提交 ②事务B将数值改为2并提交。
这时数据的值为2,事务A所做的更新将会丢失。
不可重复读:
在同一事务中,两次读取同一数据,得到内容不同
事务1:查询一条记录
-------------->事务2:更新事务1查询的记录
-------------->事务2:调用commit进行提交
事务1:再次查询上次的记录
此时事务1对同一数据查询了两次,可得到的内容不同,称为不可重复读
幻影读:
同一事务中,用同样的操作读取两次,得到的记录数不相同
事务1:查询表中所有记录
-------------->事务2:插入一条记录
-------------->事务2:调用commit进行提交
事务1:再次查询表中所有记录
此时事务1两次查询到的记录是不一样的,称为幻读
脏读:事务A读到事务B未提交的数据。
为了处理这些问题,SQL标准定义了以下几种事务隔离级别
READ UNCOMMITTED 幻想读、不可重复读和脏读都允许。
READ COMMITTED 允许幻想读、不可重复读,不允许脏读
REPEATABLE READ 允许幻想读,不允许不可重复读和脏读
SERIALIZABLE 幻想读、不可重复读和脏读都不允许
Oracle数据库支持READ COMMITTED 和 SERIALIZABLE这两种事务隔离级别。所以Oracle不支持脏读
6.隐式事务提交:
①DDL语句(create,alter,drop,truncate,rename),执行commit②DCL语句(gant,revoke),执行commit
③正常退出终端。
note:如果系统崩溃,或者sqlplus不正常退出,事务回滚。
7.事务提交或者回滚之前的状态
①因为数据库缓存区的存在,数据前一次的状态可以被回复
②当前用户可以会看使用DML操作的数据的结果,但是其他用户不能看到当前用户的DML操作结果
③所有受影响的行会被锁定,其他用户不能修改。
8.显示结束事务
commit:之前所做的所有会影响数据库的操作,都会对数据库产生持久的影响。
rollback:取消之前所做的所有操作
note:事务一旦提交,不能rollback
savepoint: 保存回滚点
savepoint point_name;
rollback to point_name;回滚到指定的标记点。标记点之后所做的所有操作都会被取消,但是之前的不受影响。