字段约束条件、外键建立数据关系
unsigned id int unsigned zerofill id int(5) zerofill
create table t1( id int, name varchar(16) ); insert into t1(id) values(1); insert into t1(name) values('jason'); insert into t1(name,id) values('kevin',2);
加上限制条件之后:
create table t2( id int, name varchar(16) not null ); insert into t2(id) values(1);
# ERROR 1364 (HY000): Field 'name' doesn't have a default value insert into t2(name) values('alex');
# Query OK, 1 row affected (0.00 sec) insert into t2 values(1,'');
# Query OK, 1 row affected (0.00 sec) insert into t2 values(2,null);
# ERROR 1048 (23000): Column 'name' cannot be null
当限制了name为非空的时候,如果name不输入或者输入为null时,都会报错,没法成功添加
注意: 当name输入为' '时,是不会报错的,添加进去的name就是空.
create table t3( id int default 666, name varchar(16) default '匿名' ); insert into t3(id) values(1); insert into t3(name) values('alex'); insert into t3 values(2,'kevin');
可以看到,当我们不输入时, id或name就会显示我们输入的默认值.
unique)
单列唯一
create table t4( id int unique, name varchar(32) unique ); insert into t4 values(1,'alex'),(2,'alex');
# ERROR 1062 (23000): Duplicate entry 'alex' for key 'name'
当id和name设置为unique时, 输入两个相同的name,就会报错.
2. 联合唯一
create table t5( id int, ip varchar(32), port int, unique(ip,port) ); insert into t5 values(1,'127.0.0.1',8080),(2,'127.0.0.1',8081),(3,'127.0.0.2',8080);
# Query OK, 3 rows affected (0.00 sec) insert into t5 values(4,'127.0.0.1',8080);
# ERROR 1062 (23000): Duplicate entry '127.0.0.1-8000' for key 'ip'
ip和port放在一个元组里面,设置为联合唯一, 当ip或port只有一个相同时是可以正常插入的, 当两个都相同时会报错,没法插入.
primary key)
create table t6( id int primary key, name varchar(32) ); insert into t6(name) values('jason');
# ERROR 1364 (HY000): Field 'id' doesn't have a default value insert into t6 values(1,'kevin');
# Query OK, 1 row affected (0.00 sec) insert into t6 values(1,'jerry');
# ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
id设置为主键,当不输入id时,会报错;当输入重复的id时,也会报错.
InnoDB存储引擎规定了所有的表都必须有且只有一个主键(主键是组织数据的重要条件并且主键可以加快数据的查询速度)
- 1. 当表中没有主键也没有其他非空且唯一的字段的情况下,InnoDB会采用一个隐藏的字段作为表的主键, 隐藏意味着无法使用, 基于该表的数据查询只能一行行查找, 速度很慢
- 2. 当表中没有主键但是有其他非空且唯一的字段, 那么会从上往下将第一个该字段自动升级为主键
create table t7( id int, age int not null unique, phone bigint not null unique, birth int not null unique, height int not null unique );
说明:
我们在创建表的时候应该有一个字段用来标识数据的唯一性, 并且该字段通常情况下就是'id'(编号)字段
id nid sid pid gid uid
create table userinfo(
uid int primary key
);
create table t8( id int primary key, name varchar(32) ); insert into t8 values(1,'alex'); insert into t8 values(2,'kevin');
当仅仅只是设置主键时,需要我们自己手动输入编号.
加上auto_increment条件之后, 编号会自动增加.
create table t9( id int primary key auto_increment, name varchar(32) ); insert into t9(name) values('alex'); insert into t9(name) values('kevin');
但是自增存在一个问题, 自增不会因为数据的删除而回退,永远自增往前
如果自己设置了更大的数, 则之后按照更大的往前自增.
如果自己设置了更大的数, 则之后按照更大的往前自增.
如果删除掉所有的数据, 重新再插入数据时, id值还是接着之前的往上自增.
如果想重置某张表的主键值, 可以使用truncate t9; 清空表数据并重置主键, 但是id值还是接着之前的往上自增.
上述员工表中存在的问题:
1.表语义不明确(到底是员工还是部门) 无所谓
2.存取数据过于冗余(浪费存储空间) 无所谓
3.数据的扩展性极差 不能忽略
有没有什么方法可以一次解决上述三个问题?
将上述表一分为二:
上述的三个问题全部解决, 但是员工跟部门之间没有了关系.
我们可以给每个员工绑定部门编号:
根据相应的编号即可查找员工的部门信息, 这个编号字段我们叫做外键字段.
外键字段: 用于标识数据与数据之间关系的字段
表关系、数据关系其实意思是一样的, 只是说法上有区分.
关系总共有四种
- 一对多
- 多对多
- 一对一
- 没有关系
关系的判断可以采用'换位思考'原则.
以员工表和部门表为例 1.先站在员工表的角度 问:一名员工能否对应多个部门 答:不可以 2.再站在部门表的角度 问:一个部门能否对应多名员工 答:可以 结论:一个可以一个不可以, 那么关系就是'一对多'
针对'一对多'关系, 外键字段建在'多'的一方
注意:
1.创建表的时候一定要先创建被关联表, 否则会报错
- 关联表:有foreign字段的表
- 被关联表:被关联表绑定的表
# 被关联表 create table dep( id int primary key auto_increment, dep_name varchar(32), dep_desc varchar(64) ); # 关联表 create table emp( id int primary key auto_increment, name varchar(32), age int, dep_id int, foreign key(dep_id) references dep(id) );
2.录入表数据的时候一定要先录入被关联表
insert into dep(dep_name, dep_desc) values('讲师部','教书育人'),('安保部','保卫国土'),('财务部','发工资'); # 注意符号都得是英文格式
再录入关联表:
insert into emp(name,age,dep_id) values('jason',18,1),('kevin',28,2),('tony',56,2),('oscar',35,3),('jerry',34,3);
3.修改数据的时候, 外键字段无法修改和删除
delete from dep where id=1; # ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`db3`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`dep_id`) REFERENCES `dep` (`id`))
针对3有简化措施>>>:级联更新级联删除
create table dep1( id int primary key auto_increment, dep_name varchar(32), dep_desc varchar(64) ); create table emp1( id int primary key auto_increment, name varchar(32), age int, dep_id int, foreign key(dep_id) references dep1(id) on update cascade on delete cascade );
更改被关联表中的信息:
外键其实是强耦合, 不符合解耦合的特性
所以很多时候, 实际项目中当表较多的情况, 我们可能不会使用外键, 而是使用代码建立逻辑层面的关系
以书籍表与作者表为例
1.先站在书籍表的角度 问:一本书能否对应多个作者 答:可以 2.再站在作者表的角度 问:一个作者能否对应多本书 答:可以 结论:两个都可以 关系就是'多对多'
针对'多对多'不能在表中直接创建, 需要新建第三张关系表
create table book( id int primary key auto_increment, title varchar(32), price float(5,2) ); create table author( id int primary key auto_increment, name varchar(32), phone bigint ); create table book2author( id int primary key auto_increment, author_id int, foreign key(author_id) references author(id) on update cascade on delete cascade, book_id int, foreign key(book_id) references book(id) on update cascade on delete cascade );
1.先站在用户表的角度 问:一个用户能否对应多个用户详情 答:不可以 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 );
注: 一对一的关系, 必须把外键字段设置为唯一