【MySQL】第3回 主键与外键

1. 约束条件之主键

1.1 primary key主键

1.1.1 单从约束角度上而言主键等价于非空且唯一 not null unique

create table t1(
id int primary key,
name varchar(32)
);
# 验证非空
insert into t1(name) values('jason');
# 验证唯一
insert into t1(id,name) values(1,'jaosn');
insert into t1(id,name) values(1,'zhang');


1.1.2 InnoDB存储引擎规定一张表必须有且只有一个主键

  1. 如果创建的表中没有主键也没有非空且唯一的字段,那么InnoDB存储引擎会自动采用一个隐藏的字段作为主键(主键可以加快数据查询:新华字典的目录)
  2. 如果创建的表中没有主键但是有非空且唯一的字段,那么InnoDB存储引擎会自动将该字段设置为主键
create table t2(
id int not null unique,
cid int not null unique,
name varchar(32)
);
desc t2;

1.1.3 创建表的时候都应该有一个'id'字段,并且该字段应该作为主键

  1. 命名不限 可以是id,cid,aid,pid....
  2. 补充说明
单列主键 联合主键
id int primary key sid int,
nid int,
primary key(sid,nid) 联合主键
最常见 联合主键也属于单列主键

1.2 auto_increment自增

1.2.1 该约束添加不能单独使用,必须跟在键后面(主要配合主键一起使用)

create table t3(
id int auto_increment
);

create table t3(
id int primary key auto_increment,
name varchar(32)
);
desc t3;
insert into t3(name) values('jason'),('zhang'),('li');
select * from t3;


1.2.2 自增特点

  1. 自增的操作不会因为执行删除数据的操作而回退或者重置
delete from t3 where id='3';
insert into t3(name) values('zhang'),('wang');
select * from t3; 
delete from t3;
insert into t3(name) values('jason'),('li');
select * from t3;



2. 如果非要重置主键,需要格式化表,truncate 表名; 删除表数据并重置主键值

truncate t3;
insert into t3(name) values('jason'),('li');
select * from t3;

2. 约束条件之外键

2.1 外键前戏

2.1.1.需要创建一张员工表

  1. 上说表的缺陷
    1. 表结构不清晰,到底是员工表还是部门表
    2. 字段数据反复存取,浪费存储空间
    3. 表的扩展性极差,牵一发动全身
  2. 优化操作>>>:拆表
    1. id name gender
    2. id dep_name dep_desc
  3. 拆表之后解决了上述的三个问题,但是出现了一个致命的缺陷,不知道数据是那个部门,也不知道部门有那个员工
  4. 解决措施,添加一个部门编号字段填写部门数据的主键值dep_id
  5. 外键字段:专用于记录表于表之间数据的关系

2.2 外键字段的创建

2.2.1 外键字段是用来记录表与表之间数据的关系,而数据的关系有四种

  1. 一对多关系
  2. 多对多关系
  3. 一对一关系
  4. 没有关系

2.2.2 Foregin key

  1. 步骤
    1. 先写普通字段
    2. 然后再写外键字段
  2. 理解(一对多代码演示)
    1. 创建表的时候需要先创建被关联的表(没有外键),然后再是关联表(有外键)
    2. 插入表数据的时候,针对外键字段只能填写被关联表字段已经出现过的数据值
    3. 被关联字段无法修改和删除,有点不太好,操作限制性太强
  3. 级联更新,级联删除(一对多代码演示)
    1. 被关联数据一旦变动,关联的数据同步变动
    2. 级联更新 on update cascade
    3. 级联删除 on delete cascade
  4. 扩展
    1. 在实际工作中,很多时候可能并不会使用外键,因为外键增加了表之间的耦合度,不便于单独操作,资源消耗增加
    2. 我们为了能够描述出表数据的关系,又不想使用外键,自己通过写SQL,建立代码层面的关系

3. 外键数据关系(换位思考)

3.1 一对多

3.1.1 针对员工表和部门表判断数据关系

  1. 先站在员工表的角度
    问:一条员工数据能否对应多条部门数据
    翻:一名员工能否属于多个部门
    答:不可以
  2. 再站在部门表的角度
    问:一条部门数据能否对应多条员工数据
    翻:一个部门能否拥有多个员工
    答:可以
  3. 结论
    1. 完成换位思考之后得出的答案 一个可以一个不可以
    2. 那么表关系就是"一对多",部门是一 员工是多
    3. 针对'一对多'的关系 外键字段建在多的一方
  4. 注意
    没有多对一,统一称为一对多

3.1.2 语句实现

# 一对多
# 先创建没外键的表
create table dep(
id int primary key auto_increment,
dep_name varchar(32),
dep_desc varchar(32)
);
# 在创建有外键的表
create table emp(
id int primary key auto_increment,
name varchar(32),
gender enum('male','female') default 'male',
dep_id int,
foreign key(dep_id) references dep(id)
);
# 针对外键字段只能填写被关联表字段已经出现过的数据值,插入空时也成功
insert into emp(name) values('jason')
select * from emp:
insert into emp(name,dep_id) values('li',10)
# 格式化emp
 truncate emp;
 insert into dep(dep_name,dep_desc) values('讲师部',1),('安保部',2);
# 报错只能填写被关联表字段已经出现过的数据值
 insert into emp(name,dep_id) values('jason',4);
 insert into emp(name,dep_id) values('jason',1);
# 被关联字段无法修改和删除
delete from dep where id=2;
delete from dep where id=1;
update dep set id= 200 where id=1;


create table dep1(
id int primary key auto_increment,
dep_name varchar(32),
dep_desc varchar(32)
);
create table emp1(
id int primary key auto_increment,
name varchar(32),
gender enum('male','female') default 'male',
dep_id int,
foreign key(dep_id) references dep1(id)
on update cascade
on delete cascade
);
insert into dep1(dep_name,dep_desc) values('讲师部','教书'),('安保部','维护');
insert into emp1(name,dep_id) values('jason',1),('wang',2),('zhao',2);
update dep1 set id=20 where id=1;
delete from dep1 where id=20;
select * from dep1;
select * from emp1;

3.2 多对多

3.2.1 以书籍表和作者表为例

  1. 先站在书籍表的角度
    问:一条书籍数据能否对应多条作者数据
    答:可以
  2. 再站在作者表的角度
    问:一条作者数据能否对应多条书籍数据
    答:可以
  3. 总结
    1. 两边都可以 那么表数据关系就是'多对多'
    2. 针对多对多表关系 外键字段不能建在任意一方。
    3. 需要单独开设第三张关系表 存储数据关系

3.2.2 语句实现

# 针对多对多表关系 外键字段不能建在任意一方。
create table book(
id int primary key auto_increment,
title varchar(32),
author_id int,
foreign key(author_id) references author(id)
on update cascade  # 级联更新
on delete cascade  # 级联删除
);
create table author(
id int primary key auto_increment,
name varchar(32),
book_id int,
foreign key(book_id) references book(id)
on update cascade # 级联更新
on delete cascade # 级联删除
);

# 需要单独开设第三张关系表 存储数据关系
create table book(
id int primary key auto_increment,
title varchar(32)
);
create table author(
id int primary key auto_increment,
name varchar(32)
);
create table book2author(
id int primary key auto_increment,
book_id int,
foreign key(book_id) references book(id)
on update cascade  
on delete cascade,
author_id int,
foreign key(author_id) references author(id)
on update cascade
on delete cascade
);

3.3 一对一

3.3.1 以用户表和用户详情表

  1. 先站在用户表的角度
    问:一条用户表数据能否对应多条用户详情表数据
    答:不可以
  2. 再站在用户详情表的角度
    问:一条用户详情表数据能否对应多条用户表数据
    答:不可以
  3. 总结
    1. 两边都不可以,那么先考虑是不是没有关系
    2. 如果有关系那么肯定就是'一对一'
    3. 针对'一对一'的表关系 外键字段建在任何一张表都可以,但是建议建在查询频率较高的表中便于后续查询

3.3.2 语法实现

# 唯一性,要不然和一对多没区别
create table userdetail(
id int primary key auto_increment,
phone bigint
);
create table user(
id int primary key auto_increment,
name varchar(32),
detail_id int unique, # 唯一性,要不然和一对多没区别
foreign key(detail_id) references userdetail(id)
on update cascade
on delete cascade
);

4. 作业

4.1 服务器表与应用程序表 一对多

create table server(
id int primary key auto_increment,
name varchar(32)
);
create table program(
id int primary key auto_increment,
name varchar(32),
server_id int,
foreign key(server_id) references server(id)
on update cascade
on delete cascade
);

4.2 课程表与班级表 多对多

create table course(
id int primary key auto_incerment,
name varchar(32)
);
create table class(
id int primary key auto_incerment,
name varchar(32)
);
create table unite(
id int primary key auto_incerment,
course_id int,
foreign key(course_id) references course(id)
on update cascade
on delete cascade
class_id int,
foreign key(class_id) referenxces class(id)
on update cascade
on delete cascade
);

4.3 学生表与班级表 一对多

create table clss(
id int primary key auto_increment,
name varchar(32)
);
create table student(
id int primary key auto_increment,
name varchar(32),
class_id int,
foreign key(class_id) references class(id)
on update cascade
on delete cascade
);

4.4 老师表与课程表 多对多

create table course(
id int primary key auto_incerment,
name varchar(32)
);
create table teacher(
id int primary key auto_incerment,
name varchar(32)
);
create table unite(
id int primary key auto_incerment,
course_id int,
foreign key(course_id) references course(id)
on update cascade
on delete cascade
teacher_id int,
foreign key(teacher_id) referenxces teacher(id)
on update cascade
on delete cascade
);

4.5 书籍表与出版社表 多对多

create table book(
id int primary key auto_incerment,
name varchar(32)
);
create table publish(
id int primary key auto_incerment,
name varchar(32)
);
create table unite(
id int primary key auto_incerment,
book_id int,
foreign key(book_id) references book(id)
on update cascade
on delete cascade
publish_id int,
foreign key(publish_id) referenxces publish(id)
on update cascade
on delete cascade
);
posted @ 2022-08-16 20:27  |相得益张|  阅读(45)  评论(0编辑  收藏  举报