【MySQL】完整性约束 -- 2019-08-17 03:19:07

原文: http://blog.gqylpy.com/gqy/249

"


目录

not null

default

unique

单列唯一

联合唯一

primary key

单列主键

复合主键

auto_increment

步长与偏移量

foreign key


约束条件与数据类型的宽度一样,都是可选参数
作用:用于保证数据的完整性和一致性

主要分为:

  • primary key (pk)    # 标识该字段为该表的主键,能够唯一的标识记录
  • foreign key (pk)    # 标识该字段为该表的外键
  • not null    # 标识该字段不能为空
  • unique key (uk)    # 标识该字段的值是唯一的
  • auto_increment    # 标识该字段的值自动增长(整数类型,而且为主键)
  • default    # 为该字段设置默认值
  • unsigned    # 无符号
  • zerofill    # 使用0填充

说明:

  1. 是否允许为空,默认为null,设置not null,使字段不允许为空,必须赋值.
  2. 字段是否有默认值,缺省的默认值是null,如果插入记录时不给字段赋值,则此字段使用默认值null.
    (设置枚举的默认值,且不为空:sex enum('boy', 'girl') not null default 'boy'
    (设置年龄必须为正值(无符号)且不为空,默认为20:age int unsigned not null default 20

 



not null

设置not null,插入值时不能为空.


   
   
  1. # 创建测试表
  2. mysql> create table test( id int not null);
  3. Query OK, 0 rows affected (0.08 sec)
  4. # 此时查看表结构,Null的标识为NO,即不允许为空
  5. mysql> desc test;
  6. + -------+---------+------+-----+---------+-------+
  7. | Field | Type | Null | Key | Default | Extra |
  8. + -------+---------+------+-----+---------+-------+
  9. | id | int(11) | NO | | NULL | |
  10. + -------+---------+------+-----+---------+-------+
  11. 1 row in set ( 0.00 sec)
  12. # 插入一个空字符串是可以的(本人是在Mac系统上实测,这一步骤可能与Windows或Linux有差异)
  13. mysql> insert into test values();
  14. Query OK, 1 row affected, 1 warning (0.03 sec)
  15. # 插入null时,直接报错
  16. mysql> insert into test values( null);
  17. ERROR 1048 (23000): Column 'id' cannot be null
  18. # 此时查询记录
  19. # 可见:int类型设置not null后,插入空字符串会替换成0
  20. mysql> select * from test;
  21. + ----+
  22. | id |
  23. + ----+
  24. | 0 |
  25. + ----+
  26. 1 row in set ( 0.00 sec)

default

设置一个字段有默认值后,则无论这个字段是null还是not null,都可以插入空,插入空默认填入default指定的默认值.


   
   
  1. # 第一种情况:default
  2. mysql> create table test( id int default 1);
  3. Query OK, 0 rows affected (0.07 sec)
  4. mysql> desc test;
  5. + -------+---------+------+-----+---------+-------+
  6. | Field | Type | Null | Key | Default | Extra |
  7. + -------+---------+------+-----+---------+-------+
  8. | id | int(11) | YES | | 1 | |
  9. + -------+---------+------+-----+---------+-------+
  10. 1 row in set ( 0.00 sec)
  11. mysql> insert into test values();
  12. Query OK, 1 row affected (0.04 sec)
  13. mysql> select * from test;
  14. + ------+
  15. | id |
  16. + ------+
  17. | 1 |
  18. + ------+
  19. 1 row in set ( 0.00 sec)
  20. # 第二种情况: not null + default
  21. mysql> create table test( id int not null default 2);
  22. Query OK, 0 rows affected (0.05 sec)
  23. mysql> desc test;
  24. + -------+---------+------+-----+---------+-------+
  25. | Field | Type | Null | Key | Default | Extra |
  26. + -------+---------+------+-----+---------+-------+
  27. | id | int(11) | NO | | 2 | |
  28. + -------+---------+------+-----+---------+-------+
  29. 1 row in set ( 0.00 sec)
  30. mysql> insert into test values();
  31. Query OK, 1 row affected (0.04 sec)
  32. mysql> select * from test;
  33. + ----+
  34. | id |
  35. + ----+
  36. | 2 |
  37. + ----+
  38. 1 row in set ( 0.00 sec)

unique

中文翻译:不同的。在MySQL中称为单列唯一

单列唯一


   
   
  1. # 创建unique方式1:
  2. # 指定name唯一
  3. mysql> create table test(
  4. -> id int,
  5. -> name char( 3) unique
  6. -> );
  7. Query OK, 0 rows affected (0.17 sec)
  8. # 插入相同的name,直接报错
  9. mysql> insert into test values( 1, 'zyk'), ( 2, 'zyk');
  10. ERROR 1062 (23000): Duplicate entry 'zyk' for key 'name'
  11. # 此时正常
  12. mysql> insert into test values( 1, 'zyk'), ( 2, 'xhh');
  13. Query OK, 2 rows affected (0.01 sec)
  14. Records: 2 Duplicates: 0 Warnings: 0
  15. # 创建unique方式2:
  16. mysql> create table test(
  17. -> id int,
  18. -> name char( 3),
  19. -> unique( id),
  20. -> unique( name)
  21. -> );
  22. Query OK, 0 rows affected (0.09 sec)
  23. # 可见:Key标识为UNI
  24. mysql> desc test;
  25. + -------+---------+------+-----+---------+-------+
  26. | Field | Type | Null | Key | Default | Extra |
  27. + -------+---------+------+-----+---------+-------+
  28. | id | int(11) | YES | UNI | NULL | |
  29. | name | char(3) | YES | UNI | NULL | |
  30. + -------+---------+------+-----+---------+-------+
  31. 2 rows in set ( 0.00 sec)

联合唯一

即指定表中两条或以上的记录,只有当这些被指定的记录都相同时才符合联合唯一,否则不会被限制.


   
   
  1. mysql> create table test(
  2. -> ip char( 15),
  3. -> port int,
  4. -> unique(ip, port) # 联合唯一
  5. -> );
  6. Query OK, 0 rows affected (0.08 sec)
  7. # 此时查看表结构,Key的标识为MUL
  8. mysql> desc test;
  9. + -------+----------+------+-----+---------+-------+
  10. | Field | Type | Null | Key | Default | Extra |
  11. + -------+----------+------+-----+---------+-------+
  12. | ip | char(15) | YES | MUL | NULL | |
  13. | port | int(11) | YES | | NULL | |
  14. + -------+----------+------+-----+---------+-------+
  15. 2 rows in set ( 0.00 sec)
  16. # 插入两条不完全相同的数据
  17. mysql> insert into test values
  18. -> ( '192.168.1.1', 3306),
  19. -> ( '192.168.1.2', 3306);
  20. Query OK, 2 rows affected (0.03 sec) # 成功插入
  21. Records: 2 Duplicates: 0 Warnings: 0
  22. # 再插入一条存在的数据,被阻止
  23. mysql> insert into test values( '192.168.1.1', 3306);
  24. ERROR 1062 (23000): Duplicate entry '192.168.1.1 -3306' for key 'ip'

primary key

一张表中可以:单列做主键,多列做主键(复合主键)
约束:字段的值不为空且值唯一,等价于not null unique
MySQL的存储引擎默认是InnoDB,对于InnoDB存储引擎来说,一张表必须有一个主键.

单列主键


   
   
  1. mysql> create table test(
  2. -> id int primary key, # 单列主键
  3. -> name char( 3)
  4. -> );
  5. Query OK, 0 rows affected (0.05 sec)
  6. # 此时查看表结构,Key的标识为PRI
  7. mysql> desc test;
  8. + -------+---------+------+-----+---------+-------+
  9. | Field | Type | Null | Key | Default | Extra |
  10. + -------+---------+------+-----+---------+-------+
  11. | id | int(11) | NO | PRI | NULL | |
  12. | name | char(3) | YES | | NULL | |
  13. + -------+---------+------+-----+---------+-------+
  14. 2 rows in set ( 0.00 sec)
  15. # 插入两条 id不同的数据
  16. mysql> insert into test values
  17. -> ( 1, 'zyk'),
  18. -> ( 2, 'xhh');
  19. Query OK, 2 rows affected (0.00 sec)
  20. Records: 2 Duplicates: 0 Warnings: 0
  21. # id已存在,阻止插入
  22. mysql> insert into test value( 2, 'jein');
  23. ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'

复合主键

复合主键与联合唯一同理:
指定表中两条或以上的记录,只有当这些被指定的记录都相同时才符合复合主键的限制,否则不会被限制.


   
   
  1. mysql> create table test(
  2. -> ip char( 15),
  3. -> port int,
  4. -> primary key(ip, port) # 复合主键
  5. -> );
  6. Query OK, 0 rows affected (0.06 sec)
  7. mysql> insert into test values
  8. -> ( '192.168.1.1', 3306),
  9. -> ( '192.168.1.2', 3306);
  10. Query OK, 2 rows affected (0.00 sec)
  11. Records: 2 Duplicates: 0 Warnings: 0
  12. mysql> insert into test values( '192.168.1.1', 3306);
  13. ERROR 1062 (23000): Duplicate entry '192.168.1.1 -3306' for key 'PRIMARY'
  14. mysql> desc test;
  15. + -------+----------+------+-----+---------+-------+
  16. | Field | Type | Null | Key | Default | Extra |
  17. + -------+----------+------+-----+---------+-------+
  18. | ip | char(15) | NO | PRI | NULL | |
  19. | port | int(11) | NO | PRI | NULL | |
  20. + -------+----------+------+-----+---------+-------+
  21. 2 rows in set ( 0.01 sec)

auto_increment

被约束的字段自动增长,且必须同时被key约束.

不指定id,则自动增长:


   
   
  1. mysql> create table test(
  2. -> id int primary key auto_increment, # 约束字段自动增长
  3. -> name varchar( 20),
  4. -> sex enum( 'boy', 'girl') default 'boy'
  5. -> );
  6. Query OK, 0 rows affected (0.05 sec)
  7. # 表结构显示Extra的标识为auto_increment,即自动增长
  8. mysql> desc test;
  9. + -------+--------------------+------+-----+---------+----------------+
  10. | Field | Type | Null | Key | Default | Extra |
  11. + -------+--------------------+------+-----+---------+----------------+
  12. | id | int(11) | NO | PRI | NULL | auto_increment |
  13. | name | varchar(20) | YES | | NULL | |
  14. | sex | enum('boy','girl') | YES | | boy | |
  15. + -------+--------------------+------+-----+---------+----------------+
  16. 3 rows in set ( 0.00 sec)
  17. # 插入两条记录
  18. mysql> insert into test( name) values ( 'zyk'), ( 'xhh');
  19. Query OK, 2 rows affected (0.00 sec)
  20. Records: 2 Duplicates: 0 Warnings: 0
  21. # 可见,id确为自动增长
  22. mysql> select * from test;
  23. + ----+------+------+
  24. | id | name | sex |
  25. + ----+------+------+
  26. | 1 | zyk | boy |
  27. | 2 | xhh | boy |
  28. + ----+------+------+
  29. 2 rows in set ( 0.00 sec)

指定id:


   
   
  1. # 指定id插入两条数据
  2. mysql> insert into test values
  3. -> ( 4, 'join', 'girl'),
  4. -> ( 7, 'lay', 'girl');
  5. Query OK, 2 rows affected (0.01 sec)
  6. Records: 2 Duplicates: 0 Warnings: 0
  7. mysql> select * from test;
  8. + ----+------+------+
  9. | id | name | sex |
  10. + ----+------+------+
  11. | 1 | zyk | boy |
  12. | 2 | xhh | boy |
  13. | 4 | join | girl |
  14. | 7 | lay | girl |
  15. + ----+------+------+
  16. 4 rows in set ( 0.00 sec)
  17. # 再次插入一条不指定 id的记录,会随着值最大的 id+ 1
  18. mysql> insert into test( name) values ( 'great white');
  19. Query OK, 1 row affected (0.00 sec)
  20. mysql> select * from test;
  21. + ----+-------------+------+
  22. | id | name | sex |
  23. + ----+-------------+------+
  24. | 1 | zyk | boy |
  25. | 2 | xhh | boy |
  26. | 4 | join | girl |
  27. | 7 | lay | girl |
  28. | 8 | great white | boy |
  29. + ----+-------------+------+
  30. 5 rows in set ( 0.00 sec)
  31. #
  32. mysql> insert into test( id, name) values ( 3, 'aaa');
  33. Query OK, 1 row affected (0.04 sec)
  34. mysql> select * from test;
  35. + ----+-------------+------+
  36. | id | name | sex |
  37. + ----+-------------+------+
  38. | 1 | zyk | boy |
  39. | 2 | xhh | boy |
  40. | 3 | aaa | boy |
  41. | 4 | join | girl |
  42. | 7 | lay | girl |
  43. | 8 | great white | boy |
  44. + ----+-------------+------+
  45. 6 rows in set ( 0.00 sec)

对于自增的字段,在用delete删除后,再插入值,改字段仍按照删除前的位置继续增长.
应使用truncate清空表,trunacte是直接清空表,再删除数据量庞大的表时非常有用.


   
   
  1. # delete删除表记录
  2. mysql> delete from test;
  3. Query OK, 8 rows affected (0.00 sec)
  4. mysql> insert into test( name) values( 'zyk');
  5. Query OK, 1 row affected (0.04 sec)
  6. # 可见: delete删除表记录后,再插入值,仍然是按照删除前的位置继续增长
  7. mysql> select * from test;
  8. + ----+------+------+
  9. | id | name | sex |
  10. + ----+------+------+
  11. | 9 | zyk | boy |
  12. + ----+------+------+
  13. 1 row in set ( 0.00 sec)
  14. # truncate清空表
  15. mysql> truncate test;
  16. Query OK, 0 rows affected (0.00 sec)
  17. mysql> insert into test( name) values( 'zyk');
  18. Query OK, 1 row affected (0.00 sec)
  19. # 此时id重新开始自增
  20. mysql> select * from test;
  21. + ----+------+------+
  22. | id | name | sex |
  23. + ----+------+------+
  24. | 1 | zyk | boy |
  25. + ----+------+------+
  26. 1 row in set ( 0.00 sec)

清空表分区 delete 与 truncate 的区别:

  • delete from tb    # 有自增id时,删除后新增的数据的id仍然是按照未删除之前最大的id+1计算的
  • truncate table tb    # 直接清空表,数据量大时非常适用,删除速度比delete快,且id直接从0开始

步长与偏移量

auto_increment_increment:步长,默认为1
auto_increment_offset:起始的偏移量,默认为1

注意:如果偏移量大于步长,则偏移量的会被重设为1


   
   
  1. # 查看步长与偏移量
  2. mysql> show variables like 'auto_i%';
  3. + --------------------------+-------+
  4. | Variable_name | Value |
  5. + --------------------------+-------+
  6. | auto_increment_increment | 1 | # 步长
  7. | auto_increment_offset | 1 | # 偏移量
  8. + --------------------------+-------+
  9. 2 rows in set ( 0.00 sec)
  10. # session为会话设置,只在本次链接中有效
  11. mysql> set session auto_increment_increment = 5;
  12. Query OK, 0 rows affected (0.00 sec)
  13. # global全局(设置后需重新连接,才会生效)
  14. mysql> set global auto_increment_increment = 5;
  15. Query OK, 0 rows affected (0.00 sec)
  16. mysql> set global auto_increment_offset = 3;
  17. Query OK, 0 rows affected (0.00 sec)
  18. # 重新连接后查看
  19. mysql> show variables like 'auto_i%';
  20. + --------------------------+-------+
  21. | Variable_name | Value |
  22. + --------------------------+-------+
  23. | auto_increment_increment | 5 |
  24. | auto_increment_offset | 3 |
  25. + --------------------------+-------+
  26. 2 rows in set ( 0.00 sec)
  27. # 先清空表
  28. mysql> truncate table test;
  29. Query OK, 0 rows affected (0.04 sec)
  30. # 插入一条记录,可见:id是从3开始计算的
  31. mysql> insert into test( name) values ( 'zyk');
  32. Query OK, 1 row affected (0.04 sec)
  33. mysql> select * from test;
  34. + ----+------+------+
  35. | id | name | sex |
  36. + ----+------+------+
  37. | 3 | zyk | boy |
  38. + ----+------+------+
  39. 1 row in set ( 0.01 sec)
  40. # 再插入几条数据,可见: id每次自增 5
  41. mysql> insert into test( name) values ( 'zyk1'), ( 'zyk2'), ( 'zyk3');
  42. Query OK, 3 rows affected (0.00 sec)
  43. Records: 3 Duplicates: 0 Warnings: 0
  44. mysql> select * from test;
  45. + ----+------+------+
  46. | id | name | sex |
  47. + ----+------+------+
  48. | 3 | zyk | boy |
  49. | 8 | zyk1 | boy |
  50. | 13 | zyk2 | boy |
  51. | 18 | zyk3 | boy |
  52. + ----+------+------+
  53. 4 rows in set ( 0.00 sec)

foreign key

一 快速理解foreign key

之前创建表的时候都是在一张表中添加记录,比如如下表:
![在这里插入图片描述](http://blog.gqylpy.com/media/ai/2019-03/c5c57780-f4f5-4916-8031-59471269e7d6.png)

公司有3个部门,但是有1个亿的员工,那意味着部门这个字段需要重复存储,部门名字越长,越浪费。
这个时候,
解决方法:
我们完全可以定义一个部门表
然后让员工信息表关联该表,如何关联,即foreign key
我们可以将上表改为如下结构:
![在这里插入图片描述](http://blog.gqylpy.com/media/ai/2019-03/fdc13268-a918-46ed-9458-6cd43d915c0e.png)

此时有两张表:
一张是employee表,简称emp表(关联表,也从从表)
一张是department表,简称dep表(被关联表,也叫主表)

注意:被关联表称为主表,关联表(也就是设置外键的表)称为从表.


   
   
  1. # 先建立主表
  2. mysql> create table dep(
  3. -> id int primary key,
  4. -> name varchar( 20) not null,
  5. -> descripe varchar( 20) not null
  6. -> );
  7. Query OK, 0 rows affected (0.07 sec)
  8. # 再建立从表
  9. mysql> create table emp(
  10. -> id int primary key,
  11. -> name varchar( 20) not null,
  12. -> age int not null,
  13. -> dep_id int,
  14. # 与主表建立关联, fk_dep为自定义的外键名,不可重复:
  15. -> constraint fk_dep foreign key(dep_id) references dep( id)
  16. -> );
  17. Query OK, 0 rows affected (0.05 sec)
  18. mysql> insert into dep values
  19. -> ( 1, "技术部", "各个大牛部们"),
  20. -> ( 2, "销售部", "一本正经胡说八道部门"),
  21. -> ( 3, "财务部", "花钱太多部门");
  22. Query OK, 3 rows affected (0.00 sec)
  23. Records: 3 Duplicates: 0 Warnings: 0
  24. mysql> insert into emp values
  25. -> ( 1, 'zyk', 19, 1),
  26. -> ( 2, 'xhh', 18, 2),
  27. -> ( 3, 'jein', 18, 3),
  28. -> ( 4, 'egon', 18, 2),
  29. -> ( 5, 'lisi', 18, 3);
  30. Query OK, 5 rows affected (0.04 sec)
  31. Records: 5 Duplicates: 0 Warnings: 0
  32. # 如果从表中有与主表中关联的行,则不允许删除主表中的被关联的行
  33. mysql> delete from dep where id= 1;
  34. ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails ( `db`. `emp`, CONSTRAINT `fk_dep` FOREIGN KEY ( `dep_id`) REFERENCES `dep` ( `id`))
  35. # 删除从表中与主表中关联的的行(dep_id= 1)
  36. mysql> delete from emp where dep_id = 1;
  37. Query OK, 1 row affected (0.03 sec)
  38. # 此时可删除主表中的数据
  39. mysql> delete from dep where id = 1;
  40. Query OK, 1 row affected (0.01 sec)
  41. mysql> select * from dep;
  42. + ----+-----------+--------------------------------+
  43. | id | name | descripe |
  44. + ----+-----------+--------------------------------+
  45. | 2 | 销售部 | 一本正经胡说八道部门 |
  46. | 3 | 财务部 | 花钱太多部门 |
  47. + ----+-----------+--------------------------------+
  48. 2 rows in set ( 0.00 sec)

同步表:
on delete cascade    # 同步删除
on update cascade    # 同步更新


   
   
  1. # 主表内容如下
  2. mysql> select * from dep;
  3. + ----+-----------+--------------------------------+
  4. | id | name | descripe |
  5. + ----+-----------+--------------------------------+
  6. | 1 | 技术部 | 各个大牛部们 |
  7. | 2 | 销售部 | 一本正经胡说八道部门 |
  8. | 3 | 财务部 | 花钱太多部门 |
  9. + ----+-----------+--------------------------------+
  10. 3 rows in set ( 0.00 sec)
  11. # 建立从表
  12. mysql> create table emp(
  13. -> id int primary key,
  14. -> name varchar( 20) not null,
  15. -> age int not null,
  16. -> dep_id int,
  17. -> constraint fk_dep foreign key(dep_id) references dep( id)
  18. -> on delete cascade # 同步删除
  19. -> on update cascade # 同步更新
  20. -> );
  21. Query OK, 0 rows affected (0.08 sec)
  22. # 从表插入以下数据
  23. mysql> select * from emp;
  24. + ----+------+-----+--------+
  25. | id | name | age | dep_id |
  26. + ----+------+-----+--------+
  27. | 1 | zyk | 19 | 1 |
  28. | 2 | xhh | 18 | 2 |
  29. | 3 | jein | 18 | 3 |
  30. | 4 | egon | 18 | 2 |
  31. | 5 | lisi | 18 | 3 |
  32. + ----+------+-----+--------+
  33. 5 rows in set ( 0.00 sec)
  34. # 同步更新
  35. mysql> update dep set id= 10 where id= 1;
  36. Query OK, 1 row affected (0.04 sec)
  37. Rows matched: 1 Changed: 1 Warnings: 0
  38. mysql> select * from dep;
  39. + ----+-----------+--------------------------------+
  40. | id | name | descripe |
  41. + ----+-----------+--------------------------------+
  42. | 2 | 销售部 | 一本正经胡说八道部门 |
  43. | 3 | 财务部 | 花钱太多部门 |
  44. | 10 | 技术部 | 各个大牛部们 |
  45. + ----+-----------+--------------------------------+
  46. 3 rows in set ( 0.00 sec)
  47. # 此时可见:与主表关联的dep_id也跟着变化了
  48. mysql> select * from emp;
  49. + ----+------+-----+--------+
  50. | id | name | age | dep_id |
  51. + ----+------+-----+--------+
  52. | 1 | zyk | 19 | 10 |
  53. | 2 | xhh | 18 | 2 |
  54. | 3 | jein | 18 | 3 |
  55. | 4 | egon | 18 | 2 |
  56. | 5 | lisi | 18 | 3 |
  57. + ----+------+-----+--------+
  58. 5 rows in set ( 0.00 sec)
  59. # 同步删除
  60. mysql> delete from dep where id= 3;
  61. Query OK, 1 row affected (0.00 sec)
  62. mysql> select * from dep;
  63. + ----+-----------+--------------------------------+
  64. | id | name | descripe |
  65. + ----+-----------+--------------------------------+
  66. | 2 | 销售部 | 一本正经胡说八道部门 |
  67. | 10 | 技术部 | 各个大牛部们 |
  68. + ----+-----------+--------------------------------+
  69. 2 rows in set ( 0.00 sec)
  70. # 此时可见:与主表关联的dep_id也被删除了
  71. mysql> select * from emp;
  72. + ----+------+-----+--------+
  73. | id | name | age | dep_id |
  74. + ----+------+-----+--------+
  75. | 1 | zyk | 19 | 10 |
  76. | 2 | xhh | 18 | 2 |
  77. | 4 | egon | 18 | 2 |
  78. + ----+------+-----+--------+
  79. 3 rows in set ( 0.00 sec)


"

原文: http://blog.gqylpy.com/gqy/249

猜你喜欢

转载自www.cnblogs.com/bbb001/p/11367202.html