MySQL--约束
约束
1. 概述
为了防止不符合规范的数据进入数据库,在用户对数据进行插入、修改、删除等操作时,DBMS自动按照一定的约束条件对数据进行监测,使不符合规范的数据不能进入数据库,以确保数据库中存储的数据正确、有效、相容。
约束条件与数据类型的宽度一样,都是可选参数,主要分为以下几种:
约束条件 | 解释 |
---|---|
NOT NULL | 非空约束,指定某列不能为空; |
UNIQUE | 唯一约束,指定某列或者几列组合不能重复 |
PRIMARY KEY | 主键,指定该列的值可以唯一地标识该列记录 |
FOREIGN KEY | 外键,指定该行记录从属于主表中的一条记录,主要用于参照完整性 |
2. NOT NULL
是否可空,null表示空,非字符串
not null - 不可空
null - 可空
2.1 实例
mysql> create table t12 (id int not null);Query OK, 0 rows affected (0.02 sec)mysql> select * from t12;Empty set (0.00 sec)mysql> desc t12;+-------+---------+------+-----+---------+-------+| Field | Type| Null | Key | Default | Extra |+-------+---------+------+-----+---------+-------+| id| int(11) | NO| | NULL||+-------+---------+------+-----+---------+-------+row in set (0.00 sec)#不能向id列插入空元素。 mysql> insert into t12 values (null);ERROR 1048 (23000): Column 'id' cannot be nullmysql> insert into t12 values (1);Query OK, 1 row affected (0.01 sec)
2.2 DEFAULT
我们约束某一列不为空,如果这一列中经常有重复的内容,就需要我们频繁的插入,这样会给我们的操作带来新的负担,于是就出现了默认值的概念。
默认值,创建列时可以指定默认值,当插入数据时如果未主动设置,则自动添加默认值。
not null + default
mysql> create table t13 (id1 int not null,id2 int not null default 222);Query OK, 0 rows affected (0.01 sec)mysql> desc t13;+-------+---------+------+-----+---------+-------+| Field | Type| Null | Key | Default | Extra |+-------+---------+------+-----+---------+-------+| id1| int(11) | NO| | NULL||| id2| int(11) | NO| | 222 ||+-------+---------+------+-----+---------+-------+rows in set (0.01 sec)# 只向id1字段添加值,会发现id2字段会使用默认值填充mysql> insert into t13 (id1) values (111);Query OK, 1 row affected (0.00 sec)mysql> select * from t13;+-----+-----+| id1 | id2 |+-----+-----+| 111 | 222 |+-----+-----+row in set (0.00 sec)# id1字段不能为空,所以不能单独向id2字段填充值;mysql> insert into t13 (id2) values (223);ERROR 1364 (HY000): Field 'id1' doesn't have a default value# 向id1,id2中分别填充数据,id2的填充数据会覆盖默认值mysql> insert into t13 (id1,id2) values (112,223);Query OK, 1 row affected (0.00 sec)mysql> select * from t13;+-----+-----+| id1 | id2 |+-----+-----+| 111 | 222 || 112 | 223 |+-----+-----+rows in set (0.00 sec)
3. UNIQUE
唯一约束,指定某列或者几列组合不能重复。
3.1 示例:
方法一:create table department1(id int,name varchar(20) unique,comment varchar(100));方法二:create table department2(id int,name varchar(20),comment varchar(100),unique(name));mysql> insert into department1 values(1,'IT','技术');Query OK, 1 row affected (0.00 sec)mysql> insert into department1 values(1,'IT','技术');ERROR 1062 (23000): Duplicate entry 'IT' for key 'name'
3.2 not null + unique
mysql> create table t1(id int not null unique);Query OK, 0 rows affected (0.02 sec)mysql> desc t1;+-------+---------+------+-----+---------+-------+| Field | Type| Null | Key | Default | Extra |+-------+---------+------+-----+---------+-------+| id| int(11) | NO| PRI | NULL||+-------+---------+------+-----+---------+-------+row in set (0.00 sec)
3.3 联合唯一
create table service(id int primary key auto_increment,name varchar(20),host varchar(15) not null,port int not null,unique(host,port) #联合唯一);mysql> insert into service values-> (1,'nginx','192.168.0.10',80),-> (2,'haproxy','192.168.0.20',80),-> (3,'mysql','192.168.0.30',3306)-> ;Query OK, 3 rows affected (0.01 sec)Records: 3 Duplicates: 0 Waings: 0mysql> insert into service(name,host,port) values('nginx','192.168.0.10',80);ERROR 1062 (23000): Duplicate entry '192.168.0.10-80' for key 'host'
4. PRIMARY KEY
主键为了保证表中的每一条数据的该字段都是表格中的唯一值。换言之,它是用来独一无二地确认一个表格中的每一行数据。
主键可以包含一个字段或多个字段。当主键包含多个栏位时,称为组合键 (Composite Key),也可以叫联合主键。
主键可以在建置新表格时设定 (运用 CREATE TABLE 语句),或是以改变现有的表格架构方式设定 (运用 ALTER TABLE)。
主键必须唯一,主键值非空;可以是单一字段,也可以是多字段组合。
4.1 单字段主键
============单列做主键===============#方法一:not null+uniquecreate table department1(id int not null unique, #主键name varchar(20) not null unique,comment varchar(100));mysql> desc department1;+---------+--------------+------+-----+---------+-------+| Field| Type | Null | Key | Default | Extra |+---------+--------------+------+-----+---------+-------+| id | int(11) | NO| PRI | NULL||| name| varchar(20) | NO| UNI | NULL||| comment | varchar(100) | YES | | NULL||+---------+--------------+------+-----+---------+-------+rows in set (0.01 sec)#方法二:在某一个字段后用primary keycreate table department2(id int primary key, #主键name varchar(20),comment varchar(100));mysql> desc department2;+---------+--------------+------+-----+---------+-------+| Field| Type | Null | Key | Default | Extra |+---------+--------------+------+-----+---------+-------+| id | int(11) | NO| PRI | NULL||| name| varchar(20) | YES | | NULL||| comment | varchar(100) | YES | | NULL||+---------+--------------+------+-----+---------+-------+rows in set (0.00 sec)#方法三:在所有字段后单独定义primary keycreate table department3(id int,name varchar(20),comment varchar(100),primary key(id); #创建主键并为其命名pk_namemysql> desc department3;+---------+--------------+------+-----+---------+-------+| Field| Type | Null | Key | Default | Extra |+---------+--------------+------+-----+---------+-------+| id | int(11) | NO| PRI | NULL||| name| varchar(20) | YES | | NULL||| comment | varchar(100) | YES | | NULL||+---------+--------------+------+-----+---------+-------+rows in set (0.01 sec)# 方法四:给已经建成的表添加主键约束mysql> create table department4(-> id int,-> name varchar(20),-> comment varchar(100));Query OK, 0 rows affected (0.01 sec)mysql> desc department4;+---------+--------------+------+-----+---------+-------+| Field| Type | Null | Key | Default | Extra |+---------+--------------+------+-----+---------+-------+| id | int(11) | YES | | NULL||| name| varchar(20) | YES | | NULL||| comment | varchar(100) | YES | | NULL||+---------+--------------+------+-----+---------+-------+rows in set (0.01 sec)mysql> alter table department4 modify id int primary key;Query OK, 0 rows affected (0.02 sec)Records: 0 Duplicates: 0 Waings: 0mysql> desc department4;+---------+--------------+------+-----+---------+-------+| Field| Type | Null | Key | Default | Extra |+---------+--------------+------+-----+---------+-------+| id | int(11) | NO| PRI | NULL||| name| varchar(20) | YES | | NULL||| comment | varchar(100) | YES | | NULL||+---------+--------------+------+-----+---------+-------+rows in set (0.01 sec)
4.2 多字段主键
==================多列做主键================create table service(ip varchar(15),port char(5),service_name varchar(10) not null,primary key(ip,port));mysql> desc service;+--------------+-------------+------+-----+---------+-------+| Field| Type| Null | Key | Default | Extra |+--------------+-------------+------+-----+---------+-------+| ip| varchar(15) | NO| PRI | NULL||| port | char(5) | NO| PRI | NULL||| service_name | varchar(10) | NO| | NULL||+--------------+-------------+------+-----+---------+-------+rows in set (0.00 sec)mysql> insert into service values-> ('172.16.45.10','3306','mysqld'),-> ('172.16.45.11','3306','mariadb')-> ;Query OK, 2 rows affected (0.00 sec)Records: 2 Duplicates: 0 Waings: 0mysql> insert into service values ('172.16.45.10','3306','nginx');ERROR 1062 (23000): Duplicate entry '172.16.45.10-3306' for key 'PRIMARY'
4.3 自动增长 auto_increment
约束字段为自动增长,被约束的字段必须同时被key约束
4.3.1 设置自动增长
#不指定id,则自动增长create table student(id int primary key auto_increment,name varchar(20),sex enum('male','female') default 'male');mysql> desc student;+-------+-----------------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+-------+-----------------------+------+-----+---------+----------------+| id| int(11)| NO| PRI | NULL| auto_increment || name | varchar(20)| YES | | NULL||| sex| enum('male','female') | YES | | male||+-------+-----------------------+------+-----+---------+----------------+mysql> insert into student(name) values-> ('nick'),-> ('tank')-> ;mysql> select * from student;+----+------+------+| id | name | sex |+----+------+------+| 1 | nick | male || 2 | tank | male |+----+------+------+#也可以指定idmysql> insert into student values(4,'asb','female');Query OK, 1 row affected (0.00 sec)mysql> insert into student values(7,'wsb','female');Query OK, 1 row affected (0.00 sec)mysql> select * from student;+----+------+--------+| id | name | sex|+----+------+--------+| 1 | nick | male|| 2 | tank | male|| 4 | asb | female || 7 | wsb | female |+----+------+--------+#对于自增的字段,在用delete删除后,再插入值,该字段仍按照删除前的位置继续增长mysql> delete from student;Query OK, 4 rows affected (0.00 sec)mysql> select * from student;Empty set (0.00 sec)mysql> insert into student(name) values('ysb');mysql> select * from student;+----+------+------+| id | name | sex |+----+------+------+| 8 | ysb | male |+----+------+------+#应该用truncate清空表,比起delete一条一条地删除记录,truncate是直接清空表,在删除大表时用它mysql> truncate student;Query OK, 0 rows affected (0.01 sec)mysql> insert into student(name) values('nick');Query OK, 1 row affected (0.01 sec)mysql> select * from student;+----+------+------+| id | name | sex |+----+------+------+| 1 | nick | male |+----+------+------+row in set (0.00 sec)
5. FOREIGN KEY
多表 :
假设我们要描述所有公司的员工,需要描述的属性有这些 : 工号 姓名 部门
公司有3个部门,但是有1个亿的员工,那意味着部门这个字段需要重复存储,部门名字越长,越浪费
解决方法: 我们完全可以定义一个部门表 然后让员工信息表关联该表,如何关联,即foreign key
5.1 foreign key 带来的约束作用
- 必须先创建主表, 再创建从表
- 在从表中插入一条记录,关联了一个主表中不存在的id , 导致插入失败, 必须保证外键的值必须是在主表中存在的
- 插入数据的顺序, 先插入主表记录, 在插入从表记录
- 从表更新外键时也必须保证, 外键的值在主表中是存在的
- 删除主表记录前 要保证从表中没有外键关联被删除的id
- 更新删除主表记录的主键时, 要保证从表中没有外键关联主表主键
5.2 示例
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) );
5.3 级联操作
当我们需要删除部门(主表)信息 时,必须先删除从表中关联的数据,很麻烦
级联操作指的就是,当你操作主表时,自动的操作从表
5.3.1 两种级联操作
-
级联的删除
当删除主表时自动删除从表中相关数据
-
级联更新
当主表的主键更新时自动的更新关联的从表数据
案例, 以上面的班级个学员为例:
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);
多表关系
1. 为什么要分表操作
有人说, 一张表不是很好吗? 分成多个表进行操作又乱又麻烦
其实不然, 就以下表为例:
看起来是不是很乱, 而且如果生产部的主管发生变更, 那所有生产部人员的Manager都需要进行相应的变更, 这样极大地增加了工作的难度和复杂度
所以我们就需要进行分表操作, 如果部门主管发生变更, 只需要改右边的表就可以了, 左边的表不需要变动
多表操作的优点:
- 节省内存空间
- 表与表之间分开, 除了外键约束之外, 没有任何关系, 修改一个表不会影响另外的表
2. 多对一
指的是从表的多条数据指向主表的同一个记录,比如员工和部门的关系, 一个部门可以有好多员工, 这就是多对一
处理方式
在多的一方保存相应的一的一方的编号
#部门: 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), );
3. 多对多
例如老师和学生, 一个学生有不同的老师来教不同的课程, 二一个老师又有很多学生, 这就是多对多关系
处理方式
建立一个中间表, 专门存放关系, 至少具备两个字段分别指向老师和学生的主键,两个字段都是外键 如下:
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));
案例
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.通过名字获取老李的idselect 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 = "老李"));
4. 一对一
如一个客户对应一个学生, 站在两边看都是一对一的关系,
处理方式,
确定先后顺序, 将先存在的数据作为主表 ,后存在的作为从表
使两个表的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 在添加详情表的数据 #将一条完整数拆分到不同表中,可以提高查询的效率,上述方式称之为垂直分表!
作者:蔚蓝的爱
来源链接:https://www.cnblogs.com/Hades123/p/11181038.html
版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。
2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。