zoukankan      html  css  js  c++  java
  • 【MySQL】完整性约束

    "


    目录

    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

    之前创建表的时候都是在一张表中添加记录,比如如下表:

    在这里插入图片描述

    公司有3个部门,但是有1个亿的员工,那意味着部门这个字段需要重复存储,部门名字越长,越浪费。
    这个时候,
    解决方法:
    我们完全可以定义一个部门表
    然后让员工信息表关联该表,如何关联,即foreign key
    我们可以将上表改为如下结构:

    在这里插入图片描述

    此时有两张表:
    一张是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)


    "
  • 相关阅读:
    close connection error java.sql.SQLRecoverableException: IO Error: Broken pipe
    Mysql 备份与恢复
    MACBOOK 破解wifi密码
    MAC 安装homebrew
    Linux(CentOS / RHEL 7) 防火墙
    ORA-01031: insufficient privileges
    Oracle登录认证
    ORA-12162: TNS:net service name is incorrectly specified
    lsnrctl: .... cannot restore segment prot after reloc: Permission denied
    CentOS / RHEL 配置yum源
  • 原文地址:https://www.cnblogs.com/zyk01/p/11375917.html
Copyright © 2011-2022 走看看