表关系

 

表关系:表与表之间(实体)有什么样的关系,每种关系应该如何设计表结构。

一对一

1:1

一对一:一张表中的一条记录与另外一张表中最多有一条明确的关系:通常,此设计方案保证两张表中使用同样的主键即可

 

学生表

学生ID(PRI)

姓名

年龄

性别

籍贯

婚否

住址

 

 

 

 

 

 

 

 

表的使用过程中:常用的信息会经常去查询,而不常用的信息会偶尔才会用到。

 

解决方案:将两张表拆分,常见的放一张表,不常见的放一张表

 

常用表

学生ID(PRI)

姓名

年龄

性别

 

 

 

 

 

不常用表

学生ID(PRI)

籍贯

婚否

住址

 

 

 

 

 

一对多

1:N  或者 N:1

一对多,通常也叫作多对一的关系。通常一对多的关系设计的方案,在“多”关系的表中去维护一个字段,这个字段是“一”关系的主键。

 

班级表  学生表

 

一对多或者是多对一 应该是多的这一个表中 要新建一个字段来保存一端的所属ID

 

多对多

 

多对多:一张表中的一条记录在另外一张表中可以匹配到多条记录,反过来也一样。

 

多对多的关系如果按照多对一的关系维护:就会出现一个字段中有多个其他表的主键,在访问的时候就会带来不便。

 

既然通过两张表自己增加字段解决不聊问题,那么就通过第三张表来解决。

 

 

 

 

多对多解决方案;增加一个中间表,让中间表与对应的其他表形成两个多对一的关系:多对一的解决方案是在“多”表中增加“一”表对应的主键字段。

 

 

外键

概念

关键字:foreign key,也叫作外键约束!

如果一个实体A的某个字段,刚好指向或者引用到另外一个实体B的主键,那么实体A的这个字段就是外键!

所以,简单来说,外键就是外面的主键,就是指向其他表的主键的那个字段!

 

 

作用

思考:为什么要有外键约束?

外键的意义就是用来约束关系内的实体,而且比较符合现实中的正常的业务逻辑!

 

 

 

所以,外键约束的作用主要就体现在以下的两个方面:

1, 增加子表记录的时候,是否有与之相对应的父表的记录

2, 当删除或更改主表记录的时候,从表中与之对应的记录应该如何处理

 

 

 

增加外键

思考:

应该在父表上定义还是在子表上定义?

应该在子表上定义!

 

 

 

Mysql中提供了两种方式增加外键

方案1:在创建表的时候增加外键(类似主键)

基本语法:在字段之后增加一条语句

[constraint `外键名`] foreign key  [`索引名`] (外键字段)  references 主表(主键);

 

 

 

 

方案2:在创建表后增加外键

Alter table 子表 add [constraint `外键名`] foreign key  [`索引名`]  (外键字段) references 主表(主键);

 

 

创建外键后会自动增加一个普通索引   可以指定普通索引的名称  也可以让系统分配

 

删除外键

外键不允许修改,只能先删除后增加

基本语法:alter table 子表 drop  foreign key 外键名字;

外键名字可以通过 show create table table_name 查看

 

 

注意:

外键不能删除产生的普通索引,只会删除外键自己

 

 

 

 

外键约束的概念

 

可以在创建外键的时候,对外键约束进行选择性的操作。

 

基本语法: Alter table 从表 add [constraint `外键名`] foreign key  [`索引名`]  (外键字段) references 主表(主键)  on 约束模式;

约束模式有三种:

1、 district:严格模式,默认的,不允许操作

2、 cascade:级联模式,一起操作,主表变化,从表数据跟着变化

3、 set null:置空模式,主表变化(删除),从表对应记录设置为空:前提是从表中对应的外键字段允许为空

 

外键约束主要约束的对象是主表操作:从表就是不能插入主表不存在的数据

 

通常在进行约束时候的时候,需要指定操作:update和delete

常用的约束模式: on update cascade, on delete set null,更新级联,删除置空

 

 

 

 

外键需要注意的问题

ü 外键约束,只能在 当前的 mysql的的 innodb 表类型(引擎)下才会生效!

ü 外键字段需要保证与关联的主表的主键字段类型完全一致

ü 因为外键有非常强大的数据约束作用,而且可能导致数据在后台变化的不可控。导致程序在进行设计开发逻辑的时候,没有办法去很好的把握数据(业务),所以外键比较少使用。

 

 

高级数据插入与查询操作

数据的操作也叫作CURD

C:create  (创建)

U:update  (更新)

R:Retrieve  (读取)

D:delete   (删除)

 

插入数据

标准语法:

insert into 表名(字段列表)  values(值列表);

扩展语法:

insert into 表名 set 字段1 = 值1,字段2=值2,字段n=值n;

一条insert into可以插入多条记录

语法:

insert into 表名(字段列表)  values(值列表), (值列表), (值列表);





蠕虫复制

就是在已有的数据的基础之上,将原来的数据进行复制,插入到对应的表中!

语法规则:
将后面的表中的所有的数据查询出来后作用前面表里面的值

insert  into 表名(字段列表)  select *|字段列表 from 表名;

下图所示:将B表中的记录插入到A表中

 

将A表中所有的记录作为值来插入到A表

 

主键重复

思考:

在进行数据插入的时候,主键已经存在,但是又需要将最新的数据更新到数据表中,怎么办?

 

语法规则:

insert into 表名(字段列表) values(值列表) 字段1=新值1,字段2=新值2……;

 

 

 

查询数据

查询数据是整个业务逻辑中使用的最多而且也是最复杂的!

 

select [字段表达式列表子表] [from子句] [where 子句] [group by 子句] [having 子句] [order by子句] [limit 子句]

 

七子句

from子句的后面的子句称五子句

注意它们的书写不能乱。

字段表达式列表子句

5+10

$v1=10;

now()

表达式与字段别名

 

 

使用as关键字为字段起别名

 

 

 

as关键字可以省略

 

凡是涉及到表达式到一定会牵扯到一个问题:优先级

 

from子句

表示查询的来源,就是表!

 

1, 可以写表名列表,使用逗号分割   from可以有多个表 每一个表之间使用逗号分割

 

 

如果此时没有条件,相当于形成了一个 笛卡尔积!

A集合的每个元素,都与B集合的每个元素之间有个关联!

 

A表的所有记录,都与B表的所有记录之间存在关联!

 

出现了同样的字段名  可以给字段取别名

 

 

2, 表的别名

如果多次出现 表名.字段名的情况,可以为表名起别名!

 

3, dual 虚拟表

 

 

where子句

where 条件表达式

 

省略where子句,相当于永远为真

 

比较运算符

> < >= <= != =

 

 

 

 

模糊查询

like。数据

可以使用 % 和 _ 作为通配符

 

 

not like,不像like取反!

 

 

 

between  and

范围比较,而且是闭区间!

比如,between 5 and 10,相当于数学上的[5,10]

 

 

 

in与not in

都属于集合运算符,用于判断前面的元素是否在或不在一个集合当中!

 

 

批量删除这个操作用的特别多

 

in,在某个集合之内

in (元素列表)

 

 

not in,不在某个集合内

not in (元素列表)

 

 

null 值的判断

不能使用普通的运算符,因为运算的结果都是null,而且不能作为查询条件!

 

 

应该使用 is null 或者 is not null 来判断!

下图是:is null

 

 

下图是:is not null

 

函数 (isnull())也可以完成类似的判断:

 

 

注意:运算符也有的优先级的概念,注意可以使用 () 来修改优先级!

 

 

select 语句

group by子句

语法

对查询结果(已经通过where子句过滤之后的数据),按照某个字段,进行分组!

 

语法:where  1  group by 字段!

 

在分组的结果中,只会显示组内的头一条记录!因此,通常,分组之后的数据,除了分组的字段外,其他字段的逻辑含义很轻!

 

分组的作用,不在查询每个组内的具体数据。而其作用主要是在分组统计上

 

 

统计函数(聚合函数)

count():求某个组内非null记录的个数,通常就用count(*)来表示  统计记录数。典型的使用是 count(*),但是除了*之外,是可以使用字段名的!

其中,只要记录存在,则count(*)就会统计到数据,而如果相应的字段为null,则count(字段)不会统计上数据:

 

 

 

下图是使用count(*)来表示

 

 

 

sum():求和,先根据某个或某几个字段进行分组,然后再对每一个组的某个字段进行相加!

 

max():求某个组内某个字段的最大值

 

min():求某个组内某个字段的最小值

 

avg():求某个组内某个字段的平均值

 

 

以班级进行分组后  只会显示组成第一个条记录

group_concat()

 

 

 

分组后排序

分组成默认是升序    ASC     DESC 降序

 

语法:

字段名  ASC(默认)|DESC

 

多字段分组

group by 字段1,字段2……

 

 

 

回溯(su)统计

其实就是向上统计!

在进行分组统计的时候,往往需要做向上统计!

比如,先统计各个班的最高分,然后就可以将各个班的最高分再进行一次统计,可以得到全年级的最高分!

 

在MySQL中,也支持回溯统计,其实就是在group by语句的后面加上with rollup即可!

 

 

having子句  

功能上与where类似,都是条件子句!

 

需求:要找到学生表中Money大于2000块钱 的学生

 

 

 

 

 

求每一个班级中平均工资大于2000块的班级

 

主要的区别,在于执行时机:

执行时机:

where,是开始时,从数据源中检索数据的条件。

而 having,是在筛选,分组之后,在得到的结果中,再次进行筛选的语法!

 

因此 having的结果 一定是 where 已经 过滤之后的结果!

 

having它就是为了配合统计函数来使用!