数据库概述_07

SELECT的执行过程

#方式1:
SELECT ...,....,...
FROM ...,...,....
WHERE 多表的连接条件 AND 不包含组函数的过滤条件
GROUP BY ...,...
HAVING 包含组函数的过滤条件
ORDER BY ... ASC/DESC
LIMIT ...,...

#方式2:
SELECT ...,....,...
FROM ...
JOIN ... ON 多表的连接条件
JOIN ... ON ...
WHERE 不包含组函数的过滤条件 AND/OR 不包含组函数的过滤条件
GROUP BY ...,...
HAVING 包含组函数的过滤条件
ORDER BY ... ASC/DESC LIMIT ...,...

#其中:
1from:从哪些表中筛选
2on:关联多表查询时,去除笛卡尔积
3where:从表中筛选的条件
4group by:分组依据
5having:在统计结果中再次筛选
6order by:排序
7limit:分页

表和表之间的关系

数据库设计方法:试凑法、规范化法和CAD法
数据库设计工具:powerdesigner

在实际开发中,一个项目经常会涉及很多方面的数据。例如产品和类目

商品编号 商品名称 价格 类别名称 等级
1 哇哈哈 2.34 饮料 3
2 茅台 456.78 饮料 3
3 Java从入门到放弃 12.45 书籍 2

数据冗余和外键

数据冗余:类别信息重复

数据冗余导致的问题:空间浪费、增加异常、删除异常和修改异常

解决方案:引入外键约束

产品表

商品编号 商品名称 商品价格 所属类别编号
1 哇哈哈 2.34 1
2 茅台 456.78 1
3 Java从入门到放弃 12.45 2

类目表

类别编号 类别名称 等级
1 饮料 3
2 书籍 2

通过引入新的表,同时使用外键约束保证取值的合理性,从而减少数据冗余

create table tb_catalog(
id bigint primary key auto_increment, -- 实体完整性
title varchar(32) not null
) comment '类别表';
create table tb_product(
id bigint primary key auto_increment comment '商品标号',
name varchar(32) not null,
price numeric(8,2) default 0,
-- 引入额外的列用于表示商品所属于的类别
catalog_id bigint, -- 外键列,允许为null
-- 外键表示该列的允许取的值必须在tb_catalog的id列中出现
foreign key(catalog_id) references tb_catalog(id)
) comment '商品表';
  • 类目表中的id为主键,产品表中的列参照于类目表中的主键,所以一般类目表会被称为主表,产品表称为从表,产品表中的catalog_id称为外键
  • 通过主表的主键和从表中的外键来描述的主外键关系,呈现的是一种一对多的关系
    • 一个类目有多个商品
    • 一个商品只能属于一个类目
  • 在MySQL中innodb支持外键和事务,MyISAM不支持外键和事务
  • 在具体开发中,为了提高性能,会故意删除外键约束,通过代码来控制数据的合理性

外键的特点

  • 从表中的外键的值是对应主表中主键值的引用
  • 从表中的外键数据类型必须和主表中的主键数据类型一致

基础语法

引入外键的目的在于保证数据的参照完整性
创建外键语法1:

create table tb_product(
id bigint primary key auto_increment comment '商品标号',
-- 引入额外的列用于表示商品所属于的类别
catalog_id bigint, -- 外键列,允许为null
-- 外键表示该列的允许取的值必须在tb_catalog的id列中出现
foreign key(catalog_id) references tb_catalog(id)
) comment '商品表';

创建外键语法2:

create table tb_product(
id bigint primary key auto_increment comment '商品标号',
catalog_id bigint -- 外键列,允许为null。是否允许为空取决于业务规则
)
-- alter table 从表名称 add [constraint fk_catalog外键约束名称] foreign key(从表中的外
键列名) references 主表名称(主表中的主键列名称)
alter table tb_product add constraint fk_catalog foreign key(catalog_id)
references tb_catalog(id);

删除外键约束的语法:

-- alter table 从表名称 drop foreign key 外键约束名称;
alter table tb_product drop foreign key fk_catalog;

需要记住 SELECT 查询时的两个顺序:

1、关键字的顺序是不能颠倒的: SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ...ORDER BY ... LIMIT...
2、SELECT语句的执行顺序:

SELECT DISTINCT player_id, player_name, count(*) as num # 顺序 5
FROM player JOIN team ON player.team_id = team.team_id # 顺序 1
WHERE height > 1.80 # 顺序 2
GROUP BY player.team_id # 顺序 3
HAVING num > 2 # 顺序 4
ORDER BY num DESC # 顺序 6
LIMIT 2 # 顺序 7

SQL的执行原理

SELECT 是先执行 FROM 这一步的。在这个阶段,如果是多张表联查,还会经历下面的几个步骤:

  1. 首先先通过 CROSS JOIN 求笛卡尔积,相当于得到虚拟表vt(virtual table)1-1;
  2. 通过 ON 进行筛选,在虚拟表 vt1-1 的基础上进行筛选,得到虚拟表 vt1-2;
  3. 添加外部行。如果我们使用的是左连接、右链接或者全连接,就会涉及到外部行,也就是在虚拟表vt1-2 的基础上增加外部行,得到虚拟表 vt1-3。

当然如果我们操作的是两张以上的表,还会重复上面的步骤,直到所有表都被处理完为止。这个过程得到是我们的原始数据。

然后进入第三步和第四步,也就是 GROUP 和 HAVING 阶段 。在这个阶段中,实际上是在虚拟表 vt2 的基础上进行分组和分组过滤,得到中间的虚拟表 vt3 和 vt4 。

当我们完成了条件筛选部分之后,就可以筛选表中提取的字段,也就是进入到 SELECT 和 DISTINCT阶段。

  • 首先在 SELECT 阶段会提取想要的字段,然后在 DISTINCT 阶段过滤掉重复的行,分别得到中间的虚拟表vt5-1 和 vt5-2 。

当我们提取了想要的字段数据之后,就可以按照指定的字段进行排序,也就是 ORDER BY 阶段 ,得到虚拟表vt6。

最后在 vt6 的基础上,取出指定行的记录,也就是 LIMIT 阶段 ,得到最终的结果,对应的是虚拟表vt7。

当然我们在写 SELECT 语句的时候,不一定存在所有的关键字,相应的阶段就会省略。

同时因为 SQL 是一门类似英语的结构化查询语言,所以在写SELECT语句时还要注意相应的关键字顺序,所谓底层运行的原理,就是执行顺序。

范式NF

设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小。

目前关系数据库有5+1级范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。如果不满足所要求的范式,则将不满足范式要求的部分进行分表。一般说来,数据库只需满足第三范式(3NF)就行了。

数据库设计中的概念

  • 实体:现实世界中客观存在并可以被区别的事物。比如“一个学生”、“一本书”、“一门课”等等。值得强调的是这里所说的“事物”不仅仅是看得见摸得着的“东西”,它也可以是虚拟的,不如说“老师与学校的关系”。
  • 属性:教科书上解释为:“实体所具有的某一特性”,由此可见,属性一开始是个逻辑概念,比如说,“性别”是“人”的一个属性。在关系数据库中,属性又是个物理概念,属性可以看作是“表的一列”。
  • 元组:表中的一行就是一个元组。
  • 分量:元组的某个属性值。在一个关系数据库中,它是一个操作原子,即关系数据库在做任何操作的时候,属性是“不可分的”。否则就不是关系数据库了。
  • 码:表中可以唯一确定一个元组的某个属性(或者属性组),如果这样的码有不止一个,那么叫候
  • 选码,从候选码中挑一个出来做老大,它就叫主码。
  • 全码:如果一个码包含了所有的属性,这个码就是全码。
  • 主属性:一个属性只要在任何一个候选码中都出现过,这个属性就是主属性。
  • 非主属性:与上面相反,没有在任何候选码中出现过,这个属性就是非主属性。
  • 外码:一个属性(或属性组),它不是码,但是它别的表的码,它就是外码。
  • 候选码: 若关系中的某一属性或属性组的值能唯一的标识一个元组,而其任何真子集都不能再标识,则称该属性组为(超级码)候选码。

主键的定义

主键可分为2大类:自然主键和代理主键。一般建议使用代理主键

  • 将表中的所有列的组合当作主键–候选码
  • 去除其中某些列查看是否还能唯一标识一行数据
  • 最后找到的所有候选码的真子集就是主码

最佳实践:可以在表中添加一个与业务无关的字段充当主键 id bigint primary keyauto_increment

NF1

所有列不可分,字段满足原子性

定义学生,学生(编号、班级编号、姓名、亲属),这个亲属列是可分的,所以将亲属列划分到另外表中,从而使剩余的列满足NF1,最终结构选择为 学生(编号、班级编号、姓名)、学生亲属(姓名、关系、外码)

NF2

消除对主键的部分依赖

定义学生,学生(编号、班级编号、姓名、宿舍楼号),主键为复合主键(编号、班级编号),这里会发现一旦班级编号确定则所属的系别就确定,系别确定则宿舍楼号确定。宿舍楼号部分依赖主键,不是依赖整个主键。解决问题的方法为分表 学生(编号、班级编号、姓名) 学生住宿 (班级编号、宿舍楼号)

NF3

消除对主键的传递依赖

定义学生,学生(学号pk、系别、宿舍楼号),主键为学号,所以自然满足NF2,但是一旦系别确定则宿舍楼号确定,所以宿舍楼号依赖于系别,不是依赖于学号。这里就是传递依赖:宿舍楼号–>系别–>学号pk。解决问题的方法为分表

范式和反范式

应用范式可以减少数据冗余,但是范式级别越高,则创建表的数量越多,查询效率则越低。所以在具体开发中经常采用降低范式要求,采用合理冗余数据的方式以提高查询效率

考虑查询效率,所以一般只达到NF3即可,甚至有时会了提高查询效率会有意降低范式要求【反范式】

经典案例:电商网站,例如京东和淘宝

商品(商品编号(pk)、商品类别)–>商品(商品编号pk,类别编号)、类目(类目标号、类目名称)

商品的数量非常庞大,而且类别要分为3个级别 101010

实际应用:商品(编号、1级类别名称、2级类别名称、3级类别名称)

表和表之间关系

表和表【实体】之间的关系有3种:

  • 一对一1:1,例如一个人只能有一个身份证,一个身份证只能属于一个人
  • 一对多或者多对一1:m或者m:1,例如一个类目可以包含多个商品,一个商品只能属于一个类目
  • 多对多n:m,例如一个学生可以选修多门课程,一个课程可以被多个学生选修

考察表【实体】之间关系的方法:中立

一对一

一对一实现方式有2种:共享主键或者唯一外键。例如人和身份证

共享主键

  • 在tb_person从表中id列即是当前表的主键,又是外键
create table tb_card(
id bigint primary key auto_increment comment '不是身份证号码,仅仅是一个非业务含义
的编号',
name varchar(32) not null,
birth date
);
create table tb_person(
id bigint primary key, -- 这里的主键值来源于tb_card的主键值,主键约束非空唯一
-- 人的编号来源于card表种的编号值,而且on delete cascade级联删除,表示删除对应的身份证
信息时会自动删除对应的用户信息
foreign key(id) references tb_card(id) on delete cascade,
salary decimal(8,2)
);

唯一外键

create table tb_card(
id bigint primary key auto_increment,
name varchar(32) not null
);
create table tb_person(
id bigint primary key auto_increment,
salary decimal(8,2),
card_id bigint not null unique,-- not null非空约束; unique唯一性约束,表示该列值不
允许重复
foreign key(card_id) references tb_card(id) on delete cascade
);

特殊实现方式

例如一夫一妻,如何在一个表中保存所有人的信息

编号(PK) 姓名 性别 妻子编号 丈夫编号
1 赵小胖 true 2 null
2 王小花 false null 1
3 张毅 true null null

另外的实现方式

编号 姓名 性别 配偶编号
1 赵小胖 true 2
2 王小花 false 1
3 张毅 true null

数据表定义

create table tb_person(
id bigint primary key auto_increment,
name varchar(10) not null,
sex boolean default 1,
pei_id bigint unique,
foreign key(pei_id) references tb_person(id)
);

一对多

实际上默认情况下fk外键参照主键pk则就是一对多关联,例如一个人有多辆车,一个车只能属于一个人

create table tb_person(
id bigint primary key,
name varchar(20)
);
create table tb_car(
id bigint primary key,
title varchar(32) not null,
person_id bigint not null,
foreign key(person_id) references tb_person(id)
);

多对多

实际上在关系型数据库中是不能直接表达多对多关系,必须引入中间表。例如学生选修课程

create table tb_student(
id bigint primary key auto_increment comment '学生编号',
name varchar(10) not null comment '学生姓名'
) comment '学生表';
create table tb_course(
id bigint primary key auto_increment comment '课程编号',
title varchar(32) not null comment '课程名称'
) comment '课程表';
create table tb_choice(
sid bigint comment '学生编号',
cid bigint comment '课程编号',
-- 不允许重复选修
primary key(sid,cid),
-- 不允许出现的学生信息错误
foreign key(sid) references tb_student(id) on delete cascade,
-- 不允许选修不存在的课程
foreign key(cid) references tb_course(id) on delete cascade
) comment '选课表,用于表示多对多关系';

PowerDesigner

Power Designer是Sybase公司的CASE工具集,使用它可以方便地对管理信息系统进行分析设计,他几乎包括了数据库模型设计的全过程

计算机辅助软件工程 CASE(Computer Aided(or Assisted)Software Engineering)。原来指用来支持管理信息系统开发的、由各种计算机辅助软件和工具组成的大型综合性软件开发环境,随着各种工具和软件技术的产生、发展、完善和不断集成,逐步由单纯的辅助开发工具环境转化为一种相对独立的方法论

优点

  • 不用在使用create table等语句创建表结构,数据库语句,可以自动生成
  • 数据库设计人员只关注如何进行数据建模即可

基本设计流程

1、创建Conceptual Data Model

  • stereotype套用模板
  • mandatory强制不可为空的意思
  • domain域可以理解为取值范围,定义最大值、最小值、约束。通过用户自定义后,新建实体时可以使用域对字段属性进行快速定义。需要Model-Domains先创建后使用

2、建立实体之间的联系

3、检查CDM:菜单栏的Tools选项,选择Check Model,打开检查模型的界面

4、将CDM转换成PDM:菜单栏的Tools选项,选择Generate Physical Data Model

5、由PDM生成sql文件:在PDM页面菜单栏中的Database点击Generate Database

猜你喜欢

转载自blog.csdn.net/qq_39756007/article/details/127214949