目录
实体
范式
数据的高级操作
数据添加
蠕虫复制
连接查询
交叉连接
内连接
外连接
自然连接
实体之间的关系分为三种:一对一、一对多(多对一)、多对多
一对一:在一个实体中,一条记录只能与另一个实体中的一个记录进行对应,反之亦然
一对多:在一个实体中,一条记录能够对应另一个实体中的多条记录;反之,另一个实体中的一条记录只能对应该实体中的一条记录,这种关系为一对多
例如:母亲与子女问题,解决两个实体的联系问题,应该在子女表中添加字段,指向唯一的母亲
多对多:在一个实体中,一条记录能够对应另一个实体中的多条记录;反之,另一个实体中的一条记录也能对应该实体的多条记录
例如:学生与教室问题,解决方案为增加一个中间关系表,将多对多关系(学生表与老师表)转化为一对多(中间表对老师表、中间表与学生表)问题,用来解决两个表之间的关联问题
范式:normal format,其目的是使结构更合理,消除存储异常,使数据冗余尽量小,便于插入、删除和更新
目前关系数据库六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。满足最低要求的范式是第一范式(1NF);在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。一般来说,数据库只需满足第三范式(3NF)即可
范式的要求是逐步严格的,即上层范式必须满足下层范式
第一范式(1NF):所谓第一范式,就是在关系模型中,对于添加的一个规范要求,所有的域都应该是原子性的,即数据库的每一列都是不可分割的原子数据项,而不能是集合、数组、记录等非原子数据项。也就是说,在实体中有多个属性时,必须拆分为不同的属性。在符合第一范式表中的每个域值只能是实体中的一个属性或属性的一部分。简而言之,第一范式就是无重复的域
在任何一个关系数据库中,满足第一范式是基本要求
第二范式(2NF):在满足第一范式的基础上,第二范式要求数据表中的每个实例或记录必须可以被唯一的区分。选取一个能够区分每个实体的属性或属性组,作为实体的主键(一般复合主键会导致不满足第二范式的问题)
第二范式要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,简而言之,第二范式就算再第一范式的基础上完全依赖于主键
第三范式(3NF):简而言之,第三范式要求一个关系中不包含已在其它关系已包含的非主关键字信息,也就是说,任何非主属性不得传递于主属性
如果设计数据表时,有一个字段并不直接依赖主键,而是通过依赖于一个非主键,最终实现主键依赖,这种依赖关系为传递依赖
解决方案:将存在传递依赖的字段以及依赖的字段本身取出单独成表
逆规范化(反范式)
规范化的优点是明显的,它避免了大量的数据冗余,节省了存储空间,保持了数据的一致性。但是范式越高代表表的划分越细致,一个数据库中需要的表格也就越多,导致其在查询等操作的效率降低,这些严重的影响了系统的运行性能
基本操作:insert into 表名 [(列表名)] values(值列表);
主键冲突:当新增的数据进行插入操作时,假设主键已经存在相应的值,则称这种情况为主键冲突
主键冲突的处理方法:忽略、替、换更新
蠕虫复制能够快速的向表中添加数据(指数形式添加),常用于测试表结构的稳定性
insert into 表名1 (字段列表) select (字段列表)from 表名2; #将表2的数据插入到表1
insert into 表名1 (字段列表) seelct (字段列表) from 表名1; #将表自身的数据插入,达到成倍增长数据的效果
注意:复制的时候不要复制主键
复制创建表(仅能复制表的结构)
create table 表名 like 数据库.表名; #如果复制的数据表在同一个数据库,则不需要在表名前添加数据库名
更新数据
基本语法:update 表名 set 字段 = 值 [where 条件];
限制更新数量:update 表名 set 字段 = 值 [where 条件] [limit 更新数量];
删除数据
删除数据和更新数据相似,也能使用limit关键字限制删除数量
数据的删除不会改变自增长的数值,要想重置自增长就需要先将数据表删除再新建数据表
使用truncate会先将表删除,再重新创建一个相同的表
查询数据
select的完整语句:select [select选项] 字段列表[字段别名] from 数据源 [where子句] [groud by 子句] [having子句] [limit子句];
select选项:select对查询结果的处理方式,分类如下:
字段别名:字段名1 as 字段名2; #as可以忽略
数据源
数据的来源,通常情况下,数据的来源都是数据表
数据源分为多种:单表数据源、多表数据源、查询语句
这种连接为笛卡尔积(交叉连接)
where子句
用于判断数据,筛选子句
where子句的返回结果,0代表false,1代表true
因为在SQL中没有bool类型,而"0"在SQL中就是false,因此在SQL中的数据的起始值都是"1"
where子句的判断条件
比较运算符:>,<,>=,<=,!=,<>(不等于),=,between...and,in/not in
在SQL中,虽然其可以作为赋值运算符,但"="一般作为比较运算符而非赋值运算符
逻辑运算符:&&,||,!
where语句的原理:where是从磁盘中选取数据时就在进行判断的条件,从磁盘取出一条记录,开始进行where判断,如果判断结果成立,就将记录保存到内存中,如果失败则直接放弃;
查询满足三个条件中任意一个的记录
select * from 表名 where 条件1 || 条件2 || 条件3; #逻辑运算符
select * from 表名 where in(条件1,条件2,条件3); #集合
查询结果在一个区间的所有数据
select * from 表名 where 字段名 >= start && 字段名 <= end;
select * from 表名 where 字段名 between start and end; #between是闭区间
group by子句
分组语句
分组的目的在于统计记录,SQL提供了一系列的统计函数,分组后每个分组只保留一个记录
count() #统计分组中的记录数
max() #统计分组中的最大值
min() #统计分组中的最小值
avg() #统计分组中的平均值
sum() #统计分组中的总和
例:select 字段名1,count(*) from 表名 group by 字段名1;
将表中记录按照字段名1进行分组,显示分组记录总数
使用count()函数时,可以输入的参数有两种:*和字段名
*代表统计记录,字段名代表统计对应的字段(NULL不统计)
多字段分组:先将记录按照一个字段分组, 再将分组后的结果按照第二个字段进行分组
回溯统计
with rollup:每个分组统计之后会有一个组,最后再向上级汇报一次统计结果
having 子句
having子句和where子句一样,是进行条件判断的,它们的不同之处在于where子句是针对磁盘数据进行判断,在数据进入内存之后,会进行分组操作,之后where子句便不能对分组结果进行操作,而having子句则正是处理这种结果的
where使用的名字只能是字段名,而不能是别名
order by子句
order by子句的作用是排序,依赖校对集对某个字段进行升序或者降序排序
例如:order by 字段名 [asc|desc]; #asc是升序,默认
多字段排序:先按照一个字段进行排序,之后将已经排序完成的分组按照第二个字段进行再次排序
limit子句
limit子句是一种限制子句,可以限制数量
limit的两种使用方法:
limit的起始值是从0开始的
limit的主要作用为实现数据的分页
连接查询:将多张表的信息按照某个指定的条件进行拼接
连接查询的分类:外连接、内连接、自然连接和交叉连接
cross join,将表中的每个记录循环取出和另外的表中进行匹配,且匹配结果全部保留,最终形成笛卡尔积
左表 cross jion 右表; #不建议使用,没有实际意义
inner join,将左表中的每一条数据都取出与右表数据进行匹配,如果两张表中的数据相同才会保留,否则不保留
左表 join 右表 on 坐标.字段 = 右表.字段; #其中on可用where代替,但on的效率更高
如上图所示,查询结果中包含重复字段
如果内连接后没有连接条件(on ...),那么查询结果为笛卡尔积
字段别名以及表别名:在查询数据的时候,不同的表有同名字段,这时需要加上表名才能区分两者,而有时表名过于繁琐,这时就可以使用字段别名或表别名
例如:select name as n form student;
以某张表为主(左表或右表),取出所有的记录,然后每一条与另一张表进行连接,不论能否匹配成功,最终都会保留;如果不能匹配成功,则副表中的数据被置为空
外连接分为两种:左外连接和右外连接
例如:左表 left/right join 右表 on 左表.字段 = 右表.字段;
自然连接:nature join,系统自动以字段名作为匹配连接条件,如果有多个同名字段,则将多个字段都作为匹配条件,连接之后,自动和并同名字段
内连接和外连接也可以模拟自然连接,使用同名字段作为连接条件,自动合并条件
例如:内连接语句/外连接语句 + using(字段名);