MySQL: 5.约束

约束

文章目录

  • 约束
    • 一、主键约束 `PRIMARY KEY`
      • 创建表时设置主键约束
        • (1)定义列时设置主键约束
        • (2)定义完所有列之后设置主键约束
        • (3)创建表时设置复合主键
      • 修改表时添加主键约束
      • 修改主键约束
    • 二、外键约束 `FOREIGN KEY`
      • 在创建表时设置外键约束
      • 在修改表时添加外键约束
      • 删除外键约束
    • 三、唯一约束 `UNIQUE`
      • 定义列时添加唯一约束
      • 修改表时添加唯一约束
      • 删除唯一约束
    • 四、检查约束 `CHECK`
      • MySQL忽略`CHECK`
      • 创建表时设置检查约束
      • 在修改表时添加检查约束
      • 删除检查约束
      • `TRIGGER`触发器示例
    • 五、默认值约束 `DEFAULT`
      • 创建表时设置默认值约束
      • 修改表时设置默认值约束 `CHANGE` | `MODIFY`
      • 删除默认值约束 `DEFAULT NULL`
    • 六、非空约束 `NOT NULL`
      • 创建表时设置非空约束
      • 修改表时设置非空约束 `CHANGE` | `MODIFY`
      • 删除非空约束 `NULL`
    • 七、查看约束
      • `SHOW CREATE TABLE`查看约束
      • `information_schema`数据库中查询约束
    • 参考

一、主键约束 PRIMARY KEY

MySQL 主键约束是一个列或者列的组合,其值能唯一地标识表中的每一行。这样的一列或多列称为表的主键,通过它可以强制表的实体完整性。

主键约束即在表中定义一个主键来唯一确定表中每一行数据的标识符。主键可以是表中的某一列或者多列的组合,其中由多列组合的主键称为复合主键。

主键应该遵守下面的规则:

  • 每个表只能定义一个主键。
  • 唯一性原则。主键值必须唯一标识表中的每一行,且不能为NULL,即表中不可能存在两行数据有相同的主键值。
  • 最小化原则。复合主键不能包含不必要的多余列。当把复合主键的某一列删除后,如果剩下的列构成的主键仍然满足唯一性原则,那么这个复合主键是不正确的。

创建表时设置主键约束

(1)定义列时设置主键约束

在定义列的同时指定主键,语法规则如下:

<字段名> <数据类型> PRIMARY KEY [默认值],

这种方法不允许将多个列同时声明为主键,多个列同时被声明为主键的话会报错。

例子:

mysql> CREATE TABLE `stu` (`id` INT(11) PRIMARY KEY, `name` VARCHAR(20), `score` FLOAT(4,1));
Query OK, 0 rows affected (0.11 sec)

mysql> DESC `stu`;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
| score | float(4,1)  | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

(2)定义完所有列之后设置主键约束

在定义完所有列之后,指定主键的语法格式为:

<列定义1>, ..., <列定义n>, PRIMARY KEY (字段名)

例如:

mysql> CREATE TABLE `stu` (`id` INT(11), `name` VARCHAR(20), PRIMARY KEY (`id`));
Query OK, 0 rows affected (0.05 sec)

mysql> DESC `stu`;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

(3)创建表时设置复合主键

设置复合主键的话只能在所有列定义的最后统一声明主键约束,在列定义中声明主键的话只能设置单个主键,不能设置复合主键。

语法,定义完所有列之后:

<列定义1>, ..., <列定义n>, PRIMARY KEY (字段1,字段2,…,字段n)

例如:
如果没有id的话,可以将员工姓名与部门id作为复合主键。

mysql> CREATE TABLE `staff` (`name` VARCHAR(20), `deptId` INT(11), `salary` DEC(10,2), PRIMARY KEY (`name`, `deptId`));
Query OK, 0 rows affected (0.06 sec)

mysql> DESC `staff`;
+--------+---------------+------+-----+---------+-------+
| Field  | Type          | Null | Key | Default | Extra |
+--------+---------------+------+-----+---------+-------+
| name   | varchar(20)   | NO   | PRI | NULL    |       |
| deptId | int(11)       | NO   | PRI | NULL    |       |
| salary | decimal(10,2) | YES  |     | NULL    |       |
+--------+---------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

修改表时添加主键约束

ALTER TABLE <数据表名> ADD PRIMARY KEY(<列名>);

前提是表中本来没有设置主键约束,否则会报错,提示已经有主键约束。

也可以新增字段的同时将字段设为主键:

ALTER TABLE <数据表名> ADD <字段名> <字段类型> PRIMARY KEY;

例如,表staff中本来没有id字段,也没有主键约束:

mysql> ALTER TABLE `staff` ADD `id` INT(11) PRIMARY KEY;
Query OK, 0 rows affected (0.12 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> DESC `staff`;
+--------+---------------+------+-----+---------+-------+
| Field  | Type          | Null | Key | Default | Extra |
+--------+---------------+------+-----+---------+-------+
| name   | varchar(20)   | NO   |     | NULL    |       |
| deptId | int(11)       | NO   |     | NULL    |       |
| salary | decimal(10,2) | YES  |     | NULL    |       |
| id     | int(11)       | NO   | PRI | NULL    |       |
+--------+---------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

修改主键约束

修改表的主键约束需要先删除主键约束,然后再添加主键约束

ALTER TABLE <表名> DROP PRIMARY KEY;
ALTER TABLE <表名> ADD PRIMARY KEY (主键字段);

例如:

mysql> ALTER TABLE `staff` DROP PRIMARY KEY;
Query OK, 0 rows affected (0.13 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE `staff` ADD PRIMARY KEY (`id`);
Query OK, 0 rows affected (0.12 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> DESC `staff`;
+--------+---------------+------+-----+---------+-------+
| Field  | Type          | Null | Key | Default | Extra |
+--------+---------------+------+-----+---------+-------+
| name   | varchar(20)   | NO   |     | NULL    |       |
| deptId | int(11)       | NO   |     | NULL    |       |
| salary | decimal(10,2) | YES  |     | NULL    |       |
| id     | int(11)       | NO   | PRI | NULL    |       |
+--------+---------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

二、外键约束 FOREIGN KEY

外键约束(FOREIGN KEY)用来在两个表的数据之间建立链接,它可以是一列或者多列。一个表可以有一个或多个外键。

  • 外键是本表的一个字段,不是本表的主键,但对应另一个表的主键。
  • 外键对应的是参照完整性,一个表的外键可以为空值,若不为空值,则每一个外键的值必须等于另一个表中主键的某个值。
  • 定义外键后,不允许删除另一个表中具有关联关系的行。

父表和子表
外键的主要作用是保持数据的一致性、完整性。例如,部门表 tb_dept的主键是 id,在员工表 tb_emp 中有一个键 deptId 与这个 id 关联。

  • 主表(父表):对于两个具有关联关系的表而言,相关联字段中主键所在的表就是主表父表必须先于子表存在。上面的部门表就是主表(父表)。
  • 从表(子表):对于两个具有关联关系的表而言,相关联字段中外键所在的表就是从表。上面的员工表就是从表(子表)。

一个简单的判断方法:当两个表建立一对多关系的时候,"一"的那一端是父表,"多"的那一端是子表。


定义一个外键时,需要遵守下列规则:

  • 父表必须已经存在于数据库中,或者是当前正在创建的表。如果是后一种情况,则父表与子表是同一个表,这样的表称为自参照表,这种结构称为自参照完整性。
  • 必须为父表定义主键。
  • 主键不能包含空值,但允许在外键中出现空值。也就是说,只要外键的每个非空值出现在指定的主键中,这个外键的内容就是正确的。
  • 在父表的表名后面指定列名或列名的组合。这个列或列的组合必须是父表的主键或候选键。
  • 外键中列的数目必须和父表的主键中列的数目相同。
  • 外键中列的数据类型必须和父表主键中对应列的数据类型相同。

参照完整性
参照完整性是相关联的两个表之间的约束,具体的说,就是从表中每条记录外键的值必须是主表中存在的。
如果实施了参照完整性,那么当主表中没有相关记录时,就不能将记录添加到相关表中。也不能在相关表中存在匹配的记录时删除主表中的记录,更不能在相关表中有相关记录时,更改主表中的主键值。也就是说,实施了参照完整性后,对表中主键字段进行操作时系统会自动地检查主键字段,看看该字段是否被添加、修改、删除了。如果对主键的修改违背了参照完整性的要求,那么系统就会自动强制执行参照完整性。

在创建表时设置外键约束

在定义完所有的列以后:

<列定义1>, ..., <列定义n>, [CONSTRAINT <外键名>] FOREIGN KEY (字段名 [,字段名2,…]) REFERENCES <主表名> (主键列1 [,主键列2,…])
  • 外键名 为定义的外键约束的名称,一个表中不能有相同名称的外键;
  • 字段名 表示子表需要添加外健约束的字段列;
  • 主表名 即被子表外键所依赖的表的名称;
  • 主键列 表示主表中定义的主键列或者列组合。

如果不设置外键名的话会自动生成外键名,名字类似于:从表名_ibfk_1

例子,员工和部门表:

# 首先创建主表,即部门表
mysql> CREATE TABLE `dept` (`id` INT(11) PRIMARY KEY, `name` VARCHAR(40) NOT NULL, `leader` VARCHAR(30));
Query OK, 0 rows affected (0.04 sec)

# 然后创建从表,即员工表
mysql> CREATE TABLE `staff` (`id` INT(11) PRIMARY KEY, `name` VARCHAR(40) NOT NULL, `salary` DEC(10, 2), `dept_id` INT(11), FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`));
Query OK, 0 rows affected (0.03 sec)

mysql> DESC `staff`;
+---------+---------------+------+-----+---------+-------+
| Field   | Type          | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| id      | int(11)       | NO   | PRI | NULL    |       |
| name    | varchar(40)   | NO   |     | NULL    |       |
| salary  | decimal(10,2) | YES  |     | NULL    |       |
| dept_id | int(11)       | YES  | MUL | NULL    |       |
+---------+---------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

mysql> DESC `dept`;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | NO   | PRI | NULL    |       |
| name   | varchar(40) | NO   |     | NULL    |       |
| leader | varchar(30) | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

在修改表时添加外键约束

ALTER TABLE <数据表名> ADD CONSTRAINT <外键名> FOREIGN KEY(<列名>) REFERENCES <主表名> (<列名>);

例子:

# 首先创建一个没有设置外键约束的表
mysql> CREATE TABLE `staff_2` (`id` INT(11) PRIMARY KEY, `name` VARCHAR(20) NOT NULL, `dept_id` INT(11) NOT NULL);
Query OK, 0 rows affected (0.03 sec)

# 添加名为'staff_2_fk_test',约束类型为外键约束的约束
mysql> ALTER TABLE `staff_2` ADD CONSTRAINT `staff_2_fk_test` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`);
Query OK, 0 rows affected (0.08 sec)
Records: 0  Duplicates: 0  Warnings: 0

# 查看名为'staff_2_fk_test'的约束详情
mysql> SELECT * FROM information_schema.key_column_usage WHERE CONSTRAINT_NAME='staff_2_fk_test'\G
*************************** 1. row ***************************
           CONSTRAINT_CATALOG: def
            CONSTRAINT_SCHEMA: test
              CONSTRAINT_NAME: staff_2_fk_test
                TABLE_CATALOG: def
                 TABLE_SCHEMA: test
                   TABLE_NAME: staff_2
                  COLUMN_NAME: dept_id
             ORDINAL_POSITION: 1
POSITION_IN_UNIQUE_CONSTRAINT: 1
      REFERENCED_TABLE_SCHEMA: test
        REFERENCED_TABLE_NAME: dept
       REFERENCED_COLUMN_NAME: id
1 row in set (0.08 sec)

删除外键约束

ALTER TABLE <表名> DROP FOREIGN KEY <外键约束名>;

不知道外键名的话可以先通过查看约束的方法找到外键名。

例子:

mysql> ALTER TABLE `staff_2` DROP FOREIGN KEY staff_2_fk_test;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

三、唯一约束 UNIQUE

MySQL唯一约束(Unique Key要求该列唯一,允许为空,但只能出现一个空值。唯一约束可以确保一列或者几列不出现重复值。

提示:PRIMARY KEY也是不允许重复的,UNIQUEPRIMARY KEY 的区别:一个表可以有多个字段声明为 UNIQUE,但只能有一个 PRIMARY KEY 声明;声明为 PRIMAY KEY 的列不允许有空值,但是声明为 UNIQUE 的字段允许空值的存在。

定义列时添加唯一约束

在创建表时定义完某个列之后直接使用 UNIQUE 关键字指定唯一约束,语法规则如下:

<字段名> <数据类型> UNIQUE

修改表时添加唯一约束

ALTER TABLE <数据表名> ADD CONSTRAINT <唯一约束名> UNIQUE(<列名>);

删除唯一约束

ALTER TABLE <表名> DROP INDEX <唯一约束名>;

四、检查约束 CHECK

检查约束用于对表中的数据进行一些限制(比如年龄大于0等),防止插入一些非法的值,在更新表的时候会对数据进行检查。

可以在列定义的时候对列设置约束条件(基于列的CHECK约束),也可以在所有列声明完以后同时对多个列设置约束(基于表的CHECK约束)。

MySQL忽略CHECK

但是要注意,在MySQL中,设置CHECK约束是不会起作用的,MySQL语句中接收CHECK子句,但是会将其忽略,因此设置CHECK约束后任然可以插入不符合CHECK约束的数据。可能是为了保证数据库之间的数据兼容性什么的。

解决方案:

  • 允许的数据为有限个离散值。比如性别之类的数据,可以用ENUM枚举类型来进行限制。
  • 允许的数据为连续的范围值。可以通过设置TRIGGER触发器来实现。

创建表时设置检查约束

CHECK(<检查约束>)

例如:

# 设置列约束
mysql> CREATE TABLE `staff` (`id` INT(11) CHECK(`id`>0), `name` VARCHAR(20));
Query OK, 0 rows affected (0.03 sec)

# 设置表约束
mysql> CREATE TABLE `staff` (`id` INT(11), `name` VARCHAR(20), CHECK(`id`>0 AND CHAR_LENGTH(`name`)>3));
Query OK, 0 rows affected (0.05 sec)

在修改表时添加检查约束

ALTER TABLE tb_emp7 ADD CONSTRAINT <检查约束名> CHECK(<检查约束>)

删除检查约束

MySQL将CHECK子句忽略掉了,因此没有保存CHECK信息,也无需删除。

ALTER TABLE <数据表名> DROP CONSTRAINT <检查约束名>;
ALTER TABLE <数据表名> DROP CHECK <检查约束名>;

TRIGGER触发器示例

可以针对BEFORE INSERTBEFORE UPDATE设置触发器,使在插入数据或者更新数据之前检查数据有效性。

下面是设置BEFORE INSERT触发器示例:

mysql> delimiter //
mysql> CREATE TRIGGER trig_sd_check BEFORE INSERT ON Customer 
    -> FOR EACH ROW 
    -> BEGIN 
    -> IF NEW.SD<0 THEN 
    -> SET NEW.SD=0; 
    -> END IF; 
    -> END
    -> //
mysql> delimiter ;

五、默认值约束 DEFAULT

创建表时设置默认值约束

<字段名> <数据类型> DEFAULT <默认值>;

修改表时设置默认值约束 CHANGE | MODIFY

ALTER TABLE <数据表名> CHANGE [COLUMN] <旧字段名> <新字段名> <数据类型> DEFAULT <默认值>;
ALTER TABLE <数据表名> MODIFY [COLUMN] <字段名> <数据类型> DEFAULT <默认值>;

删除默认值约束 DEFAULT NULL

把默认值修改为NULL即可删除默认值约束。

ALTER TABLE <数据表名> CHANGE [COLUMN] <旧字段名> <新字段名> <数据类型> DEFAULT NULL;
ALTER TABLE <数据表名> MODIFY [COLUMN] <字段名> <数据类型> DEFAULT NULL;

六、非空约束 NOT NULL

DEFAULT NULL类似。

创建表时设置非空约束

<字段名> <数据类型> NOT NULL;

修改表时设置非空约束 CHANGE | MODIFY

ALTER TABLE <数据表名> CHANGE [COLUMN] <旧字段名> <新字段名> <数据类型> NOT NULL;
ALTER TABLE <数据表名> MODIFY [COLUMN] <字段名> <数据类型> NOT NULL;

删除非空约束 NULL

把默认值修改为NULL即可删除默认值约束。

ALTER TABLE <数据表名> CHANGE [COLUMN] <旧字段名> <新字段名> <数据类型> NULL;
ALTER TABLE <数据表名> MODIFY [COLUMN] <字段名> <数据类型> NULL;

如果表中已经有该字段值为NULL的数据,则无法修改成功,会报错。

七、查看约束

SHOW CREATE TABLE查看约束

SHOW CREATE TABLE <数据表名>;
SHOW CREATE TABLE <数据表名> \G

information_schema数据库中查询约束

约束会被保存在information_schema数据库中,可以用SHOW TABLES IN information_schema;列出该数据库中所有的表格。
约束信息在information_schema.KEY_COLUMN_USAGEinformation_schema.REFERENTIAL_CONSTRAINTS这两个表格中,information_schema.KEY_COLUMN_USAGE包含所有约束的信息。

查询的时候可以通过WHERE根据CONSTRAINT_NAME(约束名)、CONSTRAINT_SCHEMA(约束所在的数据库名)、TABLE_SCHEMA(从表所在数据库名)、TABLE_NAME(从表名)、COLUMN_NAME(从表外键字段名)、REFERENCED_TABLE_SCHEMA(主表所在数据库名)、REFERENCED_TABLE_NAME(主表名)、REFERENCED_COLUMN_NAME(主表字段名)等字段进行筛选。

# 根据主表名查看约束
SELECT * FROM information_schema.key_column_usage WHERE `REFERENCED_TABLE_NAME`='主表名';

# 根据约束名查看约束
SELECT * FROM information_schema.key_column_usage WHERE `CONSTRAINT_NAME`='约束名';

# 查看主键约束
# 查看所有的主键约束(很多,建议再加上数据库名或者表名等)
SELECT * FROM information_schema.key_column_usage WHERE `CONSTRAINT_NAME`='PRIMARY';
# 查看某个数据库中所有的主键约束
SELECT * FROM information_schema.key_column_usage WHERE `CONSTRAINT_NAME`='PRIMARY' AND `CONSTRAINT_SCHEMA`='数据库名';

SELECT constraint_name FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE `constraint_schema` = 'db_name' AND `table_name` = 'table_name';

例子:

# 查看约束名为'staff_ibfk_1'的约束
mysql> SELECT * FROM information_schema.key_column_usage WHERE CONSTRAINT_NAME='staff_ibfk_1';
+--------------------+-------------------+-----------------+---------------+--------------+------------+-------------+------------------+-------------------------------+-------------------------+-----------------------+------------------------+
| CONSTRAINT_CATALOG | CONSTRAINT_SCHEMA | CONSTRAINT_NAME | TABLE_CATALOG | TABLE_SCHEMA | TABLE_NAME | COLUMN_NAME | ORDINAL_POSITION | POSITION_IN_UNIQUE_CONSTRAINT | REFERENCED_TABLE_SCHEMA | REFERENCED_TABLE_NAME | REFERENCED_COLUMN_NAME |
+--------------------+-------------------+-----------------+---------------+--------------+------------+-------------+------------------+-------------------------------+-------------------------+-----------------------+------------------------+
| def                | test              | staff_ibfk_1    | def           | test         | staff      | dept_id     |
             1 |                             1 | test                    | dept                  | id
 |
+--------------------+-------------------+-----------------+---------------+--------------+------------+-------------+------------------+-------------------------------+-------------------------+-----------------------+------------------------+
1 row in set (0.08 sec)

# 以垂直的方式(即清单的方式)呈现
mysql> SELECT * FROM information_schema.key_column_usage WHERE CONSTRAINT_NAME='staff_ibfk_1'\G
*************************** 1. row ***************************
           CONSTRAINT_CATALOG: def
            CONSTRAINT_SCHEMA: test
              CONSTRAINT_NAME: staff_ibfk_1
                TABLE_CATALOG: def
                 TABLE_SCHEMA: test
                   TABLE_NAME: staff
                  COLUMN_NAME: dept_id
             ORDINAL_POSITION: 1
POSITION_IN_UNIQUE_CONSTRAINT: 1
      REFERENCED_TABLE_SCHEMA: test
        REFERENCED_TABLE_NAME: dept
       REFERENCED_COLUMN_NAME: id
1 row in set (0.10 sec)

参考

MySQL教程:MySQL数据库学习宝典(从入门到精通)——C语言中文网
MySQL 教程 | 菜鸟教程
参照完整性_百度百科

你可能感兴趣的:(MySQL,mysql,sql,数据库)