当前位置:   article > 正文

MYSQL基础之约束_unique字段

unique字段

前面聊增删改的时候,说到了约束,本章就这个问题聊一下,其实约束很多时候都是再创建的时候就设置或者添加的,毕竟约束毕竟对数据影响还是很大的。

概述

为什么要有约束

数据的完整性是指数据的精确性以及可靠性。他是房主数据库中存在不符合予规范的数据和防止因错误信息的输入输出造成的无效操作和错误信息而提出的。

前面聊数据类型的时候,可以看出在创建数据库的时候考虑好存储的数据类型以及数据长度,但是为了数据的完整性,SQL规范以约束的方式对表的数据进行了额外的条件限制。需要从四个方面考虑:

  • 实体完整性:例如,同一个表中,不能存在两头完全相同无法区分的记录。
  • 域完整性:这个就是一个限制,比如性别一般分男女,年龄一般不会是负数也不会超过120.
  • 引用完整性:比如超市卖的商品,必须在超市仓库里面有的。
  • 用户自定义完整性:表示数据的唯一性的不能为空。

其实约束的本质就是保证数据的完整性。

什么是约束

约束时表级的强制规定。可以在创建表时规定约束(CREATE TABLE)或者通过ALTER 语句规定约束。

但是一般约束都是在创建表时候就添加了,后期能改但是一般会很少改。

分类

分类也是根据不同的标准分不同的类别。

  • 根据约束数据列的限制:单列约束和多列约束

    • 单列约束:每个约束只约束一列。
    • 多列约束:每个约束可约束多列数据。
  • 根据约束的作用范围:列级约束和表级约束

    • 列级约束: 只能作用在一个列上,跟在列的定义后面。
    • 表级约束:可以作用在多个列上,不与列一起,而是单独定义。
  • 根据约束作用:非空约束,唯一约束

    • NOT NULL :非空约束,对公某给字段不能为空
    • UNIQUE : 唯一约束,规定某个字段在整个表中是唯一。
    • PRIMARY KEY:主键(非空且唯一)约束
    • FOREIGN KEY:外键约束
    • CHECK:检查约束 (MYSQL不知道CHECK约束,如果非要使用也可以但是没效果。)
    • DEFAULT :默认约束

    下面演示的话,我们根据约束种类进行演示,其它的分类也会捎带讲解。

查询表中约束

MYSQL方便用户对自己设置的约束进行查看,自然也会有SQL语句查看:

SELECT * FROM information_schema.TABLE_CONSTRAINTS WHERE table_name='表名'

  • 1
  • 2

演示

非空 NOT NULL

这个就是字面上的意思,限制表的某个字段不能为空,也就是说必须有值,比如员工统计的员工号或者身份证号等。

因为MYSQL默认所有类型都可以为NULL,费用约束只能出现在表对象的列上,只能为列单独限定非空,不能组合非空。一个表可以有很多列分别限定了非空,补充说一些空字符串不但能与NULL,0也不等于null。

格式:

-- 创建表的时候加入非空约束

CREATE TABLE 表的名称(
字段1  数据类型 NOT NULL,
字段2  数据类型,
[字段1  数据类型 NOT NULL]
-- 可以多个列设置不可为空,不为空的列可以在任何一个字段    
)



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

现在举例:

-- 先声明一下 创建表没有什么意义,只是为了演示效果
CREATE TABLE test(
a INT NOT NULL,
b VARCHAR(10),
c DATE
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这个是在创建表的添加了约束,也是一个单列约束,毕竟只对一个列生效,而且非空限制对本身就无法多列限制。

然后插入数据:

INSERT INTO test (a,b,c) VALUES (1,'abc','2001-01-01');
INSERT INTO test (a,b,c) VALUES (2,NULL,'2002-01-01');
INSERT INTO test (a,c) VALUES (3,'2003-01-01')
  • 1
  • 2
  • 3

在这里插入图片描述

如果插入数据a字段为空呢?

INSERT INTO test (a,b,c) VALUES (NULL,'bcd','2002-01-01');

  • 1
  • 2

在这里插入图片描述

就会报错提示该字段无法存储空值,当然为了数据库兼容性更高,这个时候会设置一个默认值,这个关键字下面聊。

还有可以尝试以下,如果修改a的值为空是否可行?

UPDATE  test SET a=NULL WHERE  a='1'
  • 1

如果是低版本比如5.0会报一个警告

在这里插入图片描述

但是会强制将空变成0

在这里插入图片描述

如果是8.0,以及5.7直接回报错:

在这里插入图片描述

如果在创建表的时候,忘了加非空约束,可以通过

ALTER TABLE test
MODIFY 字段名 字段类型  NOT NULL 
  • 1
  • 2

演示:

这个需要确定一件事情,那就是是否要上约束的字段是否本身就有空;如果有空的话?

如果字段本身数据没有空值直接用就好,如果有空值不同的版本有不同的结果

ALTER TABLE test
MODIFY b VARCHAR(10) NOT NULL 

  • 1
  • 2
  • 3

先看5.0 可以执行,但是又警告,以及空值强转

在这里插入图片描述

但是8.0版本的却直接报错

在这里插入图片描述

删除的话,其实和建表后添加一样

ALTER TABLE test
MODIFY 字段名 字段类型 
  • 1
  • 2

这个就不在演示了。

唯一约束

这个对于某些字段和某列的值不能重复,比如身份证号或者员工号不能重复。

唯一约束特点:

  • 同一个表可以有多个唯一的约束。
  • 唯一约束可以是某一个类的值唯一,也可以多个列组合的值唯一。
  • 唯一性约束允许值为空。
  • 在创建唯一约束的时候,如果不给唯一约束命名,就是默认和列名相同。
  • MYSQL会给唯一约束的列默认创建一个唯一索引。

在创建表的时候添加唯一约束。

--这个是列约束写法

CREATE TABLE 表名(
字段1 类型 UNIQUE, 
 .........   ,
-- 可以多个列设置为唯一,唯一的列可以在任何一个字段   
)


-- 表约束写法
CREATE TABLE 表名(
字段1  字段类型,
字段2 字段类型, 

[CONSTRAINT 唯一约束名]  UNIQUE(字段1,....)    
 -- 中括号内的内容 可以取消,唯一约束名默认是字段名 
 -- 前面的非空约束支持表约束
 -- 表约束的时候 如果放入多个字段,就是多列约束   
    
)


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

演示

CREATE TABLE test(
a INT UNIQUE,-- 列约束
b VARCHAR(10),
c VARCHAR(10),
d DATE,
e INT,
CONSTRAINT bc UNIQUE (b),-- 表约束
UNIQUE (c,d) -- 表约束中的多列约束
)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

通过DESC查看表

在这里插入图片描述

可以看出多列创建的唯一索引,却是MUL。

现在通过sql语句查询约束:

SELECT * FROM information_schema.TABLE_CONSTRAINTS WHERE  table_name='test'
  • 1

在这里插入图片描述

现在开始插入数据

INSERT INTO test  (`a`, `b`, `c`, `d`, `e`)  VALUES ('1', 'ab', 'ab', '2021-01-01', '1') ;


  • 1
  • 2
  • 3

然后再插入一个数据:

INSERT INTO test  (`a`, `b`, `c`, `d`, `e`)  VALUES ('1', 'ab1', 'ab1', '2021-01-02', '1') ;
  • 1

在这里插入图片描述

可以看出直接报错,因为约束了a不可以重复,,记住一点这个不可重复是本字段的数据不可重复,而不是其它列不能存储相同数据。

INSERT INTO test  (`a`, `b`, `c`, `d`, `e`)  VALUES (NULL, 'ab1', 'ab1', '2021-01-02', '2') ;
INSERT INTO test  (`a`, `b`, `c`, `d`, `e`)  VALUES (NULL, 'ab2', 'ab2', '2021-01-03', '2') ;
  • 1
  • 2

但是插入a为空的两条数据不会报错,因为a不重复的数据不包括NULL。

在这里插入图片描述

如果更新某个定义唯一的值的时候,要看是否有重复的值,比如上面的表:

UPDATE test SET a='1' WHERE d ='2021-01-03';
-- 这个不会成功会报错的。
  • 1
  • 2

在这里插入图片描述

为了方便演示,所以将a和b的值插入NULL ,然后体验以下多列约束(也成为复合约束)。

INSERT INTO test  (`a`, `b`, `c`, `d`, `e`)  VALUES (NULL, NULL, 'abc', '2021-01-04', '2') ;
-- 如果插入两次就会报错
INSERT INTO test  (`a`, `b`, `c`, `d`, `e`)  VALUES (NULL, NULL, 'abc', '2021-01-04', '2') ;
  • 1
  • 2
  • 3

现在修改一个值:

INSERT INTO test  (`a`, `b`, `c`, `d`, `e`)  VALUES (NULL, NULL, 'abc1', '2021-01-04', '2') ;
  • 1

在这里插入图片描述

可以看出如果多列的唯一约束,只要一个列修改,就可以插入,当然如果其中一个值是NULL,也是可以多次插入的:

INSERT INTO test  (`a`, `b`, `c`, `d`, `e`)  VALUES (NULL, NULL, NULL, '2021-01-05', '2') ;
INSERT INTO test  (`a`, `b`, `c`, `d`, `e`)  VALUES (NULL, NULL, NULL, '2021-01-05', '2') ;
  • 1
  • 2

在这里插入图片描述

后期添加唯一约束

格式:

-- 格式 方式1
ALTER TABLE 表名
ADD CONSTRAINT  唯一约束名   UNIQUE(字段);

-- 方式2
ALTER TABLE 表名
MODIFY 字段名 字段类型   UNIQUE;


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这个后期修改的话,也是要注意要修改的列中的数据会不会有重复的,不然也会报错。所以为什么说要在建表的时候设置而不是后期修改了,这个就不在演示了。

当然如果修改一个唯一约束和其它的列在组成一个复合唯一约束也是可以,比如:

ALTER TABLE test 
ADD CONSTRAINT aa UNIQUE(a,e) 
  • 1
  • 2

在这里插入图片描述

删除唯一约束

这个可能有点复杂,先了解一个特性。

  • 添加唯一性约束的类也会自动添加一个唯一索引(又多了一个新概念)
  • 删除唯一的约束只能通过删除唯一的索引的方式进行删除
  • 删除时需要指定唯一的碎银名,其实也就是唯一约束名一样。
  • 如果创建唯一约束时未指定名称,如果时单例就默认与列名相同,如果时组合列,就是默认设置多个列的()中的第一个列名相同。
-- 通过删除索引刹出唯一约束

ALTER TABLE test
DROP INDEX  唯一约束名
  • 1
  • 2
  • 3
  • 4

索引的问题,后面优化的时候再聊,现在知道这个概念即可。

主键

主键其时用来唯一标识表中的一行记录。主键约束相当于唯一约束+非空约束的组合,其不允许重复,也不允许出现空值。

当然其也有自己的特点:

  • 一个表最多只能有一个主键约束,建立主键约束可以在列级上创建,也可以在表级上创建。
  • 主键可以单列约束也可以多列约束。如果多列约束的复合约束,这些列都不允许为空,并且组合的值不允许重复。
  • MYSQL的主键名时PRIMARY,就算是自己命名了主键名但是也没有用。
  • 创建主键约束时,系统也会默认也会创建一个索引,不过这个索引时主键索引(主键索引会增加查询效率)如果删除主键,自动添加的主键索引也会删除。
  • 一般不要修改主键字段的值,因为主键一般作为某条数据的唯一标识。

添加主键,还是老规矩,先用创建表的时候添加

-- 列级主键约束
CREATE TABLE 表名(
字段 字段类型   PRIMARY KEY,
字段 字段类型 ,
....
-- 主键最多就一个,一般放在第一个字段。   
)

-- 表级 主键约束
CREATE TABLE 表名(
字段 字段类型,
字段 字段类型 ,
....,
[CONSTRAINT 主键名设置也白设置 ] PRIMARY KEY (字段)    
-- 主键最多就一个,一般放在第一个字段。   
)


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

现在

CREATE TABLE test(
a INT PRIMARY KEY,
b VARCHAR(10),
c DATE
)
  • 1
  • 2
  • 3
  • 4
  • 5

现在看一下其主键名:

SELECT * FROM information_schema.`TABLE_CONSTRAINTS` WHERE table_name='test';
  • 1

在这里插入图片描述

可以看出其约束的名字时 PRIMARY,用表级添加一个名字但是还是PRIMAYR。

INSERT INTO `test`.`test` (`a`, `b`, `c`)  VALUES  (1,'a','2021-01-02');
-- 然后再插入这一条数据;
  • 1
  • 2

在这里插入图片描述

如果单独这样看似乎和唯一约束没有什么区别,现在尝试插入一个主键为NULL。

INSERT INTO `test`.`test` (`a`, `b`, `c`)  VALUES  (NULL,'a','2021-01-02');
  • 1

在这里插入图片描述

这个可以看出主键无法插入NULL。

现在用表级的创建一个多列主键约束。

CREATE TABLE test1(
 a INT,
 b INT,
 c DATE ,
 CONSTRAINT da_test PRIMARY KEY(a,b) 
 )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

现在看一下主键名:

在这里插入图片描述

可以看出主键的默认名是无法修改的。

 INSERT INTO `test`.`test1` (`a`, `b`, `c`)  VALUES  (1,2,'2021-01-02');
--然后再插入一遍
  • 1
  • 2

在这里插入图片描述

可以看出会报错提示,两者字段组合的值被其它用了。为什么设置两个值都是数值呢,如果翻过是否可以用:

 INSERT INTO `test`.`test1` (`a`, `b`, `c`)  VALUES  (2,1,'2021-01-02');
  • 1

在这里插入图片描述

可以看出复合约束中如果值前后顺序不一样也不会报错,现在插入空试试。

 INSERT INTO `test`.`test1` (`a`, `b`, `c`)  VALUES  (3,NULL,'2021-01-02');
  • 1

在这里插入图片描述

可以看出复合主键约束,其中任意一个字段都不可以为空。

后期添加主键约束

当然还是老规矩,如果再修改的时候要注意数据是否满足其称为主键的条件,比如是否有空,是否又重复的值。

-- 格式1 可以多列和单列
ALTER TABLE 表名
ADD PRIMARY KEY(字段)

-- 格式2
ALTER TABLE 表名
MODIFY 字段 字段类型 PRIMARY KEY
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

很简单 就不在演示了。

删除主键

因为每个表只有一个主键,所以删除的时候格式如下:

ALTER TABLE 表名
DROP PRIMARY KEY
  • 1
  • 2

但是要补充删除了主键约束,但是非空还是存在的,如下

ALTER TABLE test1
DROP PRIMARY KEY
  • 1
  • 2

在这里插入图片描述

说实话主键一般不会删除,会涉及到表的结构(B+TREE,有时间聊)

自增列

某个字段的值自增,这个列就被称为为自增列。而这个自增列自字段必须是数值型的主键约束或者唯一约束。

特征:

  • 一个表最多只能有一个自增列
  • 当某列存储唯一值可以设置自增长,所以自增列的约束必须是主键或者唯一约束
  • 自增自然有一个顺序,所以不显示数值类型。
  • 如果自增列指定了0后者NULL,会在当前最大值的基础上自增。如果自增列手动指定了具体的值,直接赋值为具体值,后面再继续增加。一般的时候也不定义不允许出现这两个值。

在创建的时候,添加自增属性。

CREATE TABLE test(
a INT UNIQUE AUTO_INCREMENT,
b VARCHAR
)
  • 1
  • 2
  • 3
  • 4

然后插入数据

INSERT INTO `test`.`test` (  `b`) VALUES(  'a') ;
INSERT INTO `test`.`test` (  `b`) VALUES(  'b') ;
  • 1
  • 2

在这里插入图片描述

可以看出a的这一列会自动添加数。再做一个实验。

INSERT INTO `test`.`test` ( `a`, `b`) VALUES( 5, 'c') ;
INSERT INTO `test`.`test` (   `b`) VALUES(   'd') ;
  • 1
  • 2

在这里插入图片描述

可以看出这个如果直接赋值也是可以的,现在又有了一个大胆的想法。

delete from test;--删除表中数据 然后再插入数据
INSERT INTO `test`.`test` (  `b`) VALUES(  'a') ;
  • 1
  • 2

猜测一下结果,会不会还是从1开始?

在这里插入图片描述

可以看出是从删除前的数据自增列最大值+1开始。

在做一个实验

-- 如果插入要给值为1呢?
INSERT INTO `test`.`test` ( `a`, `b`) VALUES( 1, 'c') ;
  • 1
  • 2

在这里插入图片描述

可见是可以的,毕竟数据已经删除,不会被唯一约束影响。

现在再插入1个

INSERT INTO `test`.`test` (  `b`) VALUES(  'd') ;

  • 1
  • 2

在这里插入图片描述

神奇不,还是不是从2开始,自动添加为8;而且数据还是会自动排序的。

后期添加自增
-- 格式 不能用如添加主键那样 add添加
ALTER TABLE 表名
MODIFY 字段名 数值类型 [一般] auto_increment;

  • 1
  • 2
  • 3
  • 4
删除自增
-- 格式 
ALTER TABLE 表名
MODIFY 字段名 数值类型 ;
--MODIFY 字段名和类型这样即可 不会影响主键或者唯一的约束

  • 1
  • 2
  • 3
  • 4
  • 5
补充:mysql8.特性 自变量的持久化

这先看现象,比如在8.0版本一下的msyql中演示

CREATE TABLE test(
a INT UNIQUE AUTO_INCREMENT
);

insert into test values (0);
insert into test values (0);
insert into test values (0);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

然后再删除表中内容:

delete from test;
  • 1

在这里插入图片描述

前面说过如果插入数据的时候不直接输入定值,就会自动从4开始添加数据。但是现在我们先不添加,而是先重启数据库

-- 重启方式1:
命令方式: net stop mysql
          net start mysql
-- 方式2
再服务中右键
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

-- 方式3
 直接重启电脑
  • 1
  • 2

现在再向里面插入数据:

insert into test values (0);
insert into test values (0);
  • 1
  • 2

下意识认为是会从4开始,但是:

在这里插入图片描述

然后再用8.0尝试一下:

还是上面的操作啊,就不在一步一步的演示了,而是直接看结果。不过如果用命令重启8.0的话如下:

命令方式: net stop mysql80
          net start mysql80
  • 1
  • 2

在这里插入图片描述

可以看出不同了,所以说mysql8.0是持久化的,具体原因呢?

  • 8.0版本以下,对于自增的列的分配规则是有InnoDB数学字典内部一个计数器来决定的,该计数器只存在内存中,也就是内存伟华,并不会存储再磁盘中,重启的时候计数器会被初始化(查看表中数据又多少条,找出最大值)。
  • 8.0版本对于自增的列的计数器持久化再重做日志里面,重启的时候会读取整个日志。

外键约束

限定某个表的某个字段的引用完整性,简单的说某个A表的某些字段关联到B表的某个字段,而A表整个值被B中内容的范围限制。

用例子举例,比如学生选课表和课程表,学生能选的课必须是再课程表中又的学科,不然你学啥?还有客人点菜和菜单表一样,你不能点菜单没有的菜。

这个时候就要引入两个表的概念 主表(父表)和从表(子表);

  • 主表(父表):被引用的表,被参考的表。(上面举例的课程表和菜单表)
  • 从表(子表):引用被人的表,参考别人的表(上面举例的学生选课表和顾客点餐表)

其也有特点:

  • 从表的外键引用主表的列,必须是主键或者是唯一约束列,毕竟被依赖的值必须唯一。
  • 在创建外键约束时,如果不给外键约束创建名,默认的不是列名,而是自动创建一个外键名。
  • 创建表时就指定外键约束的化,先创建主表然后再创建从表,不然你引用谁。删除的时候刚好相反先删除从表或外键约束,再删除主表。
  • 主表记录被从表参考,所以一般主表记录不允许删除,如果删除数据也是先删除从表中依赖该记录的数据,然后才可以删除主表的数据。
  • 从表中指定外键约束,并且一个表可以创建多个外键约束。
  • 从表的外键列于主表的参考列的名字可以不相同,单数数据类型必须一样,逻辑意义一致,不过一般的时候最好名字也一样,这样方便查看。
  • 当创建外键约束,系统默认会再所在列上建立对应的普通索引,而且索引名时列名,不是外键的约束名(索引会增加查询效率)。删除外键约束后,必须手动删除对应的索引。

再创建表的时候添加外键约束

-- 首先需要有一个主表
CREATE TABLE 主表名(
字段1  字段类型   PRIMARY KEY,
字段2  字段类型,
.........    
)

--创建时一个从表
CREATE TABLE 从表名(
字段1  字段类型 ,
字段2  字段类型,
.........   
CONSTRAINT 外键名  FOREIGN KEY  (从表的字段) REFERENCES 主表名(主表中字段如果不知主键或者唯一约束就会报错)  
)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

现在开始演示:

CREATE TABLE table_a(
a_id INT PRIMARY KEY,
a_name VARCHAR(2)

);



CREATE TABLE table_b(
a_id INT,
b_id INT,
b_name VARCHAR(10),
CONSTRAINT b_a FOREIGN KEY (a_id) REFERENCES table_a(a_id)

);

-- 插入数据
INSERT INTO table_a VALUES (1,'语文');
INSERT INTO table_a VALUES (2,'数学');
INSERT INTO table_a VALUES (3,'英语');

INSERT INTO test.table_b  VALUES ('1', '1', '张三');
INSERT INTO test.table_b  VALUES ('2', '1', '张三');
INSERT INTO test.table_b  VALUES ('2', '2', '李四');

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

这个时候插入一个主表不存在的值试试。

INSERT INTO test.table_b  VALUES ('4', '2', '李四');
  • 1

在这里插入图片描述

可见会报错的。当然如果更新从表将其a_id变成主表中不存在的值,也会报错的,这个就不在演示了,很容易理解了。

现在删除主表的值试一下。

DELETE FROM test.table_a WHERE a_id = '1' ;
  • 1

在这里插入图片描述

删除主表中的某个被从表引用的数据也会报错,上面数据中a_id中的1被引用了,所以会报错,但是如果删除其=‘3’,就不会报错。这个就说明了如果要删除主表的数据,如果没有被引用还好,如果被引用要不删或修改从表的引用值,或者删除外键约束。

在这里插入图片描述

后期添加外键约束

前提时两者的主表中的被引用的列,以及确定时主键或者唯一约束后:

ALTER TABLE 表名
ADD  CONSTRAINT 外键名  FOREIGN KEY  (从表的字段) REFERENCES 主表名(主表中字段如果不知主键或者唯一约束就会报错)  

  • 1
  • 2
  • 3
删除外键约束

其实这个有点繁琐具体步骤如下

-- 第一步: 查看约束名
SELECT * FROM information_schema.TABLE_CONSTRAINTS WHERE table_name='表名';

ALTER TABLE 从表 
DROP FOREIGN KEY 外键约束名

-- 第二步 因为会自动带一个索引 删除索引
SHOW INDEX FORM 表名;
ALTER TABLE 从表 
DROP INDEX  索引名


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

如果有类员工表和部门表是否一定要建立外键约束,有些时候看公司要求,毕竟有些公司要求不创建,毕竟再增删改的时候会收到约束,但是其数据的完整性得到保证,但是有些公司却要求有这个约束,不然每次插入数据或者修改数据的时候有可能插入一个没关系的数据。但是外键约束对于查询速度没有什么影响。就算感觉快那也是索引的原因。

其实创建外键约束,是有成本的,需要消耗系统资源的,对于大并发数的SQL操作,有可能会不适合,保留大型网站的重要数据库,可能因外键约束而岛主系统开销变大从而变慢。所以很多时候开发者通过再插入数据之前在应用层进行一个限制,比如只能插入某些值,而不是随便插入等。

参考阿里开放手册
  • 强制 不得使用外键与级联,一切外键概念必须在应用层解决。
补充约束等级

其实外键约束也是可以设置等级的

  • Cascade方式:在主表上UPDATE/DELETE 记录时,通过删除UPDATE/DELETE 子表的对应的数据。
  • SET NULL 方式: 在主表上UPDATE/DELETE 记录时,将从表中匹配记录的列设置位NULL,但是注意从表的外键列不能设置NOT NULL 约束。
  • NO action 方式:如果从表中有匹配的记录,则不允许主表对应的候选键进行UPDATE/DELETE 操作,说白了就是从表有些主表的值被引用了也不可以修改了。
  • Resrict 方式: 同NO action,都是立即检查外键约束。
  • Set default 方式:主表有变更时,从表将外键设置成一个默认值,但是会有个兼容问题,比如Innodb不识别。在可视化工具中可能会显示空白。

一般不设置的化,默认就是Resrict 方式. 不过一般在最好也是最常用的是:ON UPDATE CASCADE ON DELETE SET NULL

现在进行演示:

CREATE TABLE table_a1(
a_id INT PRIMARY KEY,
a_name VARCHAR(2)

);



CREATE TABLE table_b1(
a_id INT,
b_id INT,
b_name VARCHAR(10),
    -- 这个地方可以如果修改表会同步,但是删除会自动设置为空
CONSTRAINT b_a1 FOREIGN KEY (a_id) REFERENCES table_a1(a_id) ON UPDATE CASCADE ON DELETE  SET NULL

);

-- 插入数据
INSERT INTO table_a1 VALUES (1,'语文');
INSERT INTO table_a1 VALUES (2,'数学');
INSERT INTO table_a1 VALUES (3,'英语');

INSERT INTO test.table_b1  VALUES ('1', '1', '张三');
INSERT INTO test.table_b1  VALUES ('2', '1', '张三');
INSERT INTO test.table_b1 VALUES ('2', '2', '李四');

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

现在执行:

UPDATE table_a1 SET a_id='4' WHERE a_id='1'

  • 1
  • 2

然后查看从表:

在这里插入图片描述

然后再删除主表中某个值

DELETE FROM  table_a1 WHERE a_id='2'

  • 1
  • 2

在这里插入图片描述

CHECK 约束

CHECK 约束的作用是检查某个字段的值是否满足某个要求,一般是值的范围(不一定是数字)。

其实在5.7版本及以前虽然可以使用check约束,但是没有效果,后面再8.0版本之后可以使用了。

CREATE TABLE 主表名(
字段1  字段类型  ,
字段2  字段类型 CHECK (值的范围).........    
)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

演示

CREATE TABLE test(
a INT CHECK (a>100),
)
-- 
INSERT INTO test VALUES (1000);
  • 1
  • 2
  • 3
  • 4
  • 5

但是插入一个小于100的数试试:

INSERT INTO test VALUES (10);
  • 1

在这里插入图片描述

当然也可以限制某些字符串:

CREATE TABLE test1(
sex CHAR CHECK ( sex IN ('男' OR '女'))
)
  • 1
  • 2
  • 3

就不在低版本演示了,毕竟低版本演示也没有什么效果。

默认约束

给某个字段或某列指定一个默认值,一旦插入是无法显示的值,就会赋值默认值。

CREATE TABLE 主表名(
字段1  字段类型  DEFAULT 默认值,
字段2  字段类型  ,
.........    
)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

演示

CREATE TABLE test(
a INT DEFAULT 10,
b VARCHAR(10)
)
INSERT INTO test VALUES (1,'a');
INSERT INTO test (b) VALUES ('b');
INSERT INTO test VALUES (NULL,'b');

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述

很多时候在创建白哦的时候会加入 NOT NULL DEFAULT ‘’ 或者 DEFAULT 0。为了不让表中出NULL,毕竟NULL 会影响比较,有时候会影响运算,而且效率不高,影响索引效果。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/574785
推荐阅读
相关标签
  

闽ICP备14008679号