数据库 级联 约束 外键
小练习:创建博客表
标题 发布时间 最后更新 作者 内容 字数
char(100) datetime timestamp char(100) longtext bigint
create table blog(
title char(100),
publish_time datetime,
last_update timestamp,
author char(100),
content longtext,
number bigint
);
insert into blog values(
"mysql 高级篇",
now(),
null,
"jerry 夫斯基",
"啥也不说了 就是很高级",
11);
select title from blog where number = 100;
上节课内容回顾
1.简单的增删改查语句
insert into table_name values(v1,v2,...);
insert into table_name(column1,column2) values(v1,v2,...);
insert into table_name values(v1,...) ,(v1,....);
delete from table_name where 条件;
update table_name set column = new_valuem,... where 条件;
select * from table_name;
select column1,... from table_name where 条件;
2.数据类型
1.整形
tyniint smallint mediumint int bigint
2.浮点
float double decimal
3.字符串
char varchar tiny | long [text blob] binary varbinary
枚举 enum
集合 set
4.日期和时间
date time datetime year timestamp
什么是约束 constraint
约束就是一种限制,例如宪法,让你不能做某些事情
数据库的约束,是对数据的安全性,完整性的保证;
mysql中的约束
关键字 | 作用描述 | 举例 |
---|---|---|
unique | 唯一性约束,表示这个字段不能出现重复的值, 用于唯一标识一条记录 | 例如身份证号码,学号等 |
not null | 非空约束,表示这个字段的值不能为空 | 例如姓名,密码 |
null | 一些数据类型默认就是可以为空的 | |
default | 默认值,用于给某一个字段设置默认值 | gender enum("g","b") default "b" |
普通约束测试
#完整的建表语句
create table table_name(字段名称 字段类型[(宽度) 约束]) charset utf8;
#学生表 具备 姓名 性别 学号
create table student(
#非空
name char(20) not null,
#默认值
gender enum("g","b") default "b",
#唯一
id int unique
)
#测试:
insert into student values(null,null,null); # 错误原因是 name 不能为空
insert into student values("jack",null,null); # 可以插入 null也是一个特殊的值 并且id的唯一约束 也可以为null
insert into student(name,id) values("jack",null); #可以插入 当没有给gender指定参数时,将使用默认值
alter table student modify id int unique not null; # 为已经存在的字段添加约束
primary key
主键约束,从约束角度来看就等同于,非空+唯一
主键与普通的约束的区别
create table person(
id char(19) primary key,
name char(20)
);
insert into person values("1","rose");# ok
insert into person values("1","jack");# ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'主键冲突;
insert into person values("2","jack"); # ok
insert into person values(null,"tom"); # Column 'id' cannot be null #主键不能为空
#从约束角度来看就等同于,非空+唯一
create table person2(
id char(19),
name char(20)
);
# 在innodb存储引擎中 ,主键用于组织数据 (树形结构)
# 也就说主键对于innodb引擎来说是必须要的,没有不行!
# 如果没有手动指定主键
# mysql 会自动查找一个具备非空且唯一的字段作为主键
# 如果也没有也没有这样的字段,mysql会创建一个隐藏字段 作为主键
# 首先明确主键是一种索引 unique也是,索引的作用是加速查询
# 如果我们在查询语句中没有使用索引字段 ,mysql将无法为我们的查询加速 意味着如果没有主键,将无法加速查询
总的来说:主键 具备约束的作用,还能加快我们的查询速度,所以今后在创建表的时候都应该创建索引字段
应该将什么样的字段设置为主键????
如果本来的业务中就存在非空且唯一的字段 那就把它设为主键 如果没有就自己添加一个字段专门作为主键
通常我们会将主键设置为类int 类型,是为了方便保证其唯一;
案例:
mysql> create table PC(
id int primary key,
pp char(20),
model char(10),
price float
);
mysql> insert into PC values(1,"IBM","1214SB",40000);
mysql> insert into PC values(2,"DELL","1200DSB",4000);
mysql> select *from PC;
mysql> select *from PC where id = 1;
mysql> select *from PC where pp = "DELL";
为主键设置自动增长
当我们创建了主键字段时,插入数据必须保证主键是唯一的不能重复,这就需要我们自己管理主键值,这是很麻烦的,所以mysql有一个自动增长的属性,可以添加在整形字段上,每次插入数据时,都可以自动的插入值,并且每次加1不会冲突;
create table teacher(
id int primary key auto_increment,
name char(10)
);
insert into teacher values(null,"jack"); # 对于自动增长的字段可以给null 也会自动生成值
insert into teacher(name) values("jack");# 也可以跳过这个字段
create table teacher3(
id char unique auto_increment ,
name char(10)
);
自动增长可以用在 具备索引,并且是数字类型的字段上,但是通常与主键一起使用!
表之间的关系
表之间的关系
foreign_key
外键约束,用于指向另一个表的主键字段
# 创建表的时候添加外键
create table teacher(
id int primary key auto_increment,
name char(20),
gender char(1),
dept_id int,
foreign key(dept_id) references dept(id)
);
解释:
foreign key(dept_id) references dept(id)
dept_id 表示当前表的外键字段
dept 表示要关联哪个表
dept(id) id表示关联的dept表的id字段
主表与从表
先有主表 再有从表
先有dept 再有teacher
foreign key 带来的约束作用
1.在从表中插入一条记录,关联了一个主表中不存在的id 导致插入失败
必须保证部门id (外键的值) 必须是在主表中存在的
2.插入数据的顺序
先插入主表记录 在插入从表记录
3.从表更新外键时也必须保证 外键的值在主表中是存在的
4.删除主表记录前 要保证从表中没有外键关联被删除的id
delete from dept where id = 1;# 报错
必须先删除从表 再删除主表
delete from teacher where dept_id = 1;
delete from dept where id = 1;
5.更新主表记录的主键时 要保证从表中没有外键关联被删除的id
6.必须先创建主表
7.删除表 必须先删除从表
强调:foreign key就是用来保证两张表之间的关联关系是正确的
练习: 班级表 和 学员表 主表是班级 从表是学员 外键加给学员
create table class(
id int primary key auto_increment,
name char(20)
);
create table student(
id int primary key auto_increment,
name char(20),
gender char(1),
c_id int,
foreign key(c_id) references class(id)
);
级联操作 cascade
当我们需要删除部门(主表)信息 时,必须先删除从表中关联的数据,很麻烦
级联操作指的就是,当你操作主表时,自动的操作从表
两种级联操作
1.级联的删除
当删除主表时自动删除从表中相关数据
2.级联更新
当主表的主键更新时自动的更新关联的从表数据
案例:以上面的班级个学员为例:
drop table if exists class;
# 如果这表存在 才执行删除 可以避免报错 if exists
# if not exists 如果不存在才执行
create table class(
id int primary key auto_increment,
name char(20)
);
insert into class values(null,"py9");
insert into class values(null,"py10");
#创建表的时候指定级联操作
drop table if exists student;
create table student(
id int primary key auto_increment,
name char(20),
gender char(1),
c_id int,
foreign key(c_id) references class(id)
on update cascade
on delete cascade
);
# 级联操作可以单独使用 也可以一起使用 空格隔开即可
insert into student values(null,"jack","m",1);
insert into student values(null,"rose","m",1);
insert into student values(null,"tom","m",2);
外键的使用
什么时候使用外键:
表之间存在关联关系 ,
首先要确定表之间的关系:
多对一
一对多(多对一)
或者
老师和部门的关系
老师的角度看
一个老师应该对应有一个部门
一个老师可以对应对多个部门? 不行 一个老师只能属于一个部门 (要看具体业务要求)!
多个老师可以对应一个部门
多对一
部门的角度看
一个部门可以对应多个老师
一个部门可以对应一个老师
多个部门可以对应一个老师? 不行
一对多
如何处理一对多(多对一)?
在老师表中存储 部门id
即多的一方存储 一的一方的id
处理方式
在一的一方即teacher表中保存相应部门(多的一方)的编号
案例:
#部门:
create table dept(
id int primary key auto_increment,
name char(20),
job char(50),
manager char(10)
);
#老师表:
create table teacher(
id int primary key auto_increment,
name char(20),
gender char(1),
dept_id int,
foreign key(t_id) references teacher(id),
);
多对多
如何确定多对多关系
例如 老师表 和 学生表
套路一样 先站在老师表 在站在学生表
老师表角度: 一个老师可以对应多个学生 一对多
学生表角度: 一个学生可以对应多个老师 一对多
如果双方都是一对多的关系 那么 两者是多对多关系
处理方式2
建立一个中间表,用于存储关系,至少具备两个字段分别指向老师和学生的主键,两个字段都是外键 如下:
create table t_s_r(
id int primary key auto_increment,
t_id int,
s_id int,
foreign key(t_id) references teacher(id),
foreign key(s_id) references student(id),
unique key(t_id,s_id)
);
上表中id是可选的,问题是如何保证没有重复的关系 ?
方式1:
给两个字段设置为联合唯一 + 非空
#假设表已经存在了
alter table t_s_r add unique key(t_id,s_id);
# 创建表时指定 多字段联合唯一
create table t_s_r2(t_id int,s_id int,unique key(t_id,s_id));
方式2:
# 推荐 将中间的关系表 两个id 作为联合主键 同时具备了 唯一且非空约束
create table t_s_r3(t_id int,s_id int,primary key(t_id,s_id));
处理多对多关系
1.创建两个主表 如学员 和 老师
2.创建关系表 包含两个字段 分别设置外键 指向对应的表
3.将两个字段 作为联合主键
案例
create table student(id int primary key auto_increment,name char(10));
create table teacher(id int primary key auto_increment,name char(10));
create table t_s_r(
t_id int,
s_id int,
foreign key(t_id) references teacher(id),
foreign key(s_id) references student(id),
primary key(t_id,s_id)
);
# 先插入 学生或是老师都可以 但是关系表一定是最后添加的
insert into teacher values(null,"bgon"),(null,"nike");
insert into student values(null,"老王"),(null,"老李");
# 老王被bgon教过
insert into t_s_r values(1,1);
# nike教过老李
insert into t_s_r values(2,2);
# nike教过老王
insert into t_s_r values(2,1);
已知老师名称为bgon 请找出他教过那些学生
1.通过名字获取 bgon的id
2.拿着id取关系表中拿到一堆学生的id
3.通过学生的id取出学生的信息
select id from teacher where name = "bgon";
select s_id from t_s_r where t_id = 1;
select * from student where id = 1;
# 子查询方式 把一条语句的结果作为另一条语句的条件!
select * from student where id = (select s_id from t_s_r where t_id = (select id from teacher where name = "bgon"));
已知学生名为老李 请查询出 哪些老师教过他
1.通过名字获取老李的id
select id from student where name = "老李";
2.拿着id去关系表 找出老师的id
select t_id from t_s_r where s_id = 2;
3.通过老师的id取出老师的信息
select name from teacher where id = x;
# 子查询方式:
select name from teacher where id = (
select t_id from t_s_r where s_id = (
select id from student where name = "老李"
)
);
一对一关系
如一个客户对应一个学生:
站在两边看都是一对一的关系
处理方式三
确定先后顺序
将先存在的数据作为主表
后存在的作为从表
使两个表的id保持一一对应
方法1: 从表的id 即是主键又是外键
方法2:从表的id设置为外键 并保证唯一
案例:
# 人员表
create table person(
id int primary key auto_increment,
name char(10),
age int
);
# 详情表
create table person_info(
id int primary key,
height float,
weight float,
foreign key(id) references person(id)
);
#再这样的关系中 必须先插入主表即person 拿到一个id 在添加详情表的数据
#将一条完整数拆分到不同表中,可以提高查询的效率,上述方式称之为垂直分表!
约束:
unique 唯一
not null 非空
null 可以为空
default 默认值
primary key 主键 ==(非空+唯一+加速查询)
auto_increment 自动增长
foreign key 外键约束 , 保证两张表的关系是完整的
级联操作: 用在外键关联中,可以级联的删除或更新从表记录