『 数据库 』MySQL复习(表的约束)
文章目录
- 表的约束
- 空与非空
- DEFAULT 约束
- COMMENT 列描述
- ZEROFILL 约束
- PRIMARY KEY 主键约束
- 复合主键
- auto_increment 自增长约束
- 唯一键
- 外键约束
- 如何判断父子表
- 综合例题
表的约束
属于表的属性, 对数据插入进行一种约束限制, 以确保数据库中数据的完整性, 正确性以及安全性;
空与非空
对表内设置可以设置空与非空约束, 表内field
默认为空属性, 即默认情况下该列的数据可以为空;
-
设置非空约束
设置非空约束时只需要在某个字段后增加
NOT NULL
即可, 创建表时的字段可以设置, 使用MODIFY
/CHANGE
都可以使用;mysql> CREATE TABLE nullTest(-> isNull INT COMMENT '默认为空',-> isNoNull INT NOT NULL COMMENT '设置非空约束'-> ); Query OK, 0 rows affected (0.02 sec)mysql> SELECT * FROM nullTest; Empty set (0.00 sec)mysql> INSERT INTO nullTest(isNull, isNoNull) VALUES(5); ERROR 1136 (21S01): Column count doesn't match value count at row 1 mysql> INSERT INTO nullTest(isNull, isNoNull) VALUES(5, 8); Query OK, 1 row affected (0.00 sec)mysql> INSERT INTO nullTest(isNull, isNoNull) VALUES(NULL, 10); Query OK, 1 row affected (0.00 sec)mysql> SELECT * FROM nullTest; +--------+----------+ | isNull | isNoNull | +--------+----------+ | 5 | 8 | | NULL | 10 | +--------+----------+ 2 rows in set (0.00 sec)mysql>
当使用
MODIFY
修改一个空约束的字段为非空约束时, 若该表内存在数据且对应列中存在NULL
时非空约束将会修改失败;mysql> DESC nullTest; +----------+------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+------+------+-----+---------+-------+ | isNull | int | YES | | NULL | | | isNoNull | int | NO | | NULL | | +----------+------+------+-----+---------+-------+ 2 rows in set (0.00 sec)mysql> SELECT * FROM nullTest; +--------+----------+ | isNull | isNoNull | +--------+----------+ | 5 | 8 | | NULL | 10 | +--------+----------+ 2 rows in set (0.00 sec)mysql> ALTER TABLE nullTest MODIFY isNull INT NOT NULL; ERROR 1138 (22004): Invalid use of NULL value mysql>
DEFAULT 约束
DEFAULT
约束为当数据插入至某一行时若没有为该field
插入数据时该field
将会有默认值;
mysql> SHOW CREATE TABLE defaultTest\G
*************************** 1. row ***************************Table: defaultTest
Create Table: CREATE TABLE `defaultTest` (`id` int DEFAULT NULL,`hasDefault` varchar(255) DEFAULT 'Set default',`notDefault` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)mysql> SELECT * FROM defaultTest;
Empty set (0.00 sec)mysql> INSERT INTO defaultTest(id) VALUES(1);
Query OK, 1 row affected (0.00 sec)mysql> SELECT * FROM defaultTest;
+------+-------------+------------+
| id | hasDefault | notDefault |
+------+-------------+------------+
| 1 | Set default | NULL |
+------+-------------+------------+
1 row in set (0.00 sec)mysql>
通常 NOT NULL
非空约束 与 DEFAULT
默认值约束是可以相互协作的约束, 即不允许非空但存在默认值, 两者协作使用可以避免使用者的漏载数据所产生的报错, 同时也避免使用者直接插入NULL
作为数据;
同时MySQL在用户创建/修改表时对语句进行优化, 当用户没有设置默认值时MySQL将会把每条COLUMN
后增加DEFAULT NULL
字段;
mysql> CREATE TABLE test_ (-> to_del INT-> );
Query OK, 0 rows affected (0.03 sec)mysql> SHOW CREATE TABLE test_\G
*************************** 1. row ***************************Table: test_
Create Table: CREATE TABLE `test_` (`to_del` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)mysql>
COMMENT 列描述
列描述约束充当一个注释的功能, 以确保表的使用者能够了解该column
需要插入的数据内容;
通常创建或者修改属性时在column
或table_name
后加上COMMENT 'comment_message....'
即可(表和字段都可增加COMMENT
约束);
mysql> DESC commentTest;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| test_ | int | YES | | NULL | |
+-------+------+------+-----+---------+-------+
1 row in set (0.01 sec)mysql> DROP TABLE commentTest;
Query OK, 0 rows affected (0.01 sec)mysql> CREATE TABLE commentTest( test_ INT COMMENT "It's a column_comment" ) COMMENT "It's a table_column";
Query OK, 0 rows affected (0.02 sec)mysql> SHOW CREATE TABLE commentTest\G
*************************** 1. row ***************************Table: commentTest
Create Table: CREATE TABLE `commentTest` (`test_` int DEFAULT NULL COMMENT 'It''s a column_comment'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='It''s a table_column'
1 row in set (0.00 sec)
-
查看描述的方式
通过
DESC
无法查看COMMENT
注释;-
SHOW CREATE
SHOW CREATE TABLE table_name;
通过该方式能够看到创建表时的所有信息, 也包括注释(表注释和字段注释);
mysql> SHOW CREATE TABLE commentTest\G *************************** 1. row ***************************Table: commentTest Create Table: CREATE TABLE `commentTest` (`test_` int DEFAULT NULL COMMENT 'It''s a column_comment' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='It''s a table_column' 1 row in set (0.00 sec)mysql>
-
SHOW FULL COLUMNS
SHOW FULL COLUMNS FROM table_name;
通过该方式可以查看对应表内所有
column
的comment
注释;mysql> SHOW FULL COLUMNS FROM commentTest; +-------+------+-----------+------+-----+---------+-------+---------------------------------+-----------------------+ | Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment | +-------+------+-----------+------+-----+---------+-------+---------------------------------+-----------------------+ | test_ | int | NULL | YES | | NULL | | select,insert,update,references | It's a column_comment | +-------+------+-----------+------+-----+---------+-------+---------------------------------+-----------------------+ 1 row in set (0.00 sec)mysql>
-
ZEROFILL 约束
ZEROFILL
用来控制长度, 当某个数值类型后通过括号设置长度时(如INT(5)
), 对该列进行数据插入, 若数据的长度未达到所设置的宽度, 将自动为该数值填充0
, 浮点类型为后置零, 整形类型为前导零;
mysql> CREATE TABLE zerofillTest(-> num1 INT(5),-> num2 INT(5) UNSIGNED-> );
Query OK, 0 rows affected, 2 warnings (0.02 sec)mysql> DESC zerofillTest;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| num1 | int | YES | | NULL | |
| num2 | int unsigned | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)mysql> DROP TABLE zerofillTest;
Query OK, 0 rows affected (0.01 sec)mysql> CREATE TABLE zerofillTest( num1 INT(5) UNSIGNED ZEROFILL, num2 INT(5) UNSIGNED ZEROFILL);
Query OK, 0 rows affected, 4 warnings (0.02 sec)mysql> DESC zerofillTest;
+-------+--------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------------------+------+-----+---------+-------+
| num1 | int(5) unsigned zerofill | YES | | NULL | |
| num2 | int(5) unsigned zerofill | YES | | NULL | |
+-------+--------------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)mysql> INSERT INTO zerofillTest VALUES(12, 34);
Query OK, 1 row affected (0.01 sec)mysql> SELECT * FROM zerofillTest;
+-------+-------+
| num1 | num2 |
+-------+-------+
| 00012 | 00034 |
+-------+-------+
1 row in set (0.00 sec)
该约束需要配合UNSIGNED
无符号约束一同使用(负数无法使用ZEROFILL
), 若是对数值类型设置ZEROFILL
约束时没有指定UNSIGNED
约束, 那么将会自动为该数值设置UNSIGNED
;
mysql> ALTER TABLE zerofillTest ADD num5 FLOAT(5,3) ZEROFILL;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 2mysql> SHOW CREATE TABLE zerofillTest;
+--------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+--------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| zerofillTest | CREATE TABLE `zerofillTest` (`num1` int(5) unsigned zerofill DEFAULT NULL,`num2` int(5) unsigned zerofill DEFAULT NULL,`num3` float(5,3) unsigned zerofill DEFAULT NULL,`num4` int(5) unsigned zerofill DEFAULT NULL,`num5` float(5,3) unsigned zerofill DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+--------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)mysql>
PRIMARY KEY 主键约束
主键约束通常为某一个column
设置其唯一值, 且不能重复, 不能为空;
一张表内只能拥有一个主键约束;
一张表内通常为某个整数类型设置以确保对应行能够成为该表的唯一;
mysql> CREATE TABLE primary_keyTest(-> id BIGINT PRIMARY KEY,-> name VARCHAR(20),-> age INT-> );
Query OK, 0 rows affected (0.01 sec)mysql> SHOW CREATE TABLE primary_keyTest\G
*************************** 1. row ***************************Table: primary_keyTest
Create Table: CREATE TABLE `primary_keyTest` (`id` bigint NOT NULL,`name` varchar(20) DEFAULT NULL,`age` int DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)mysql> DESC primary_keyTest;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | bigint | NO | PRI | NULL | |
| name | varchar(20) | YES | | NULL | |
| age | int | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)mysql> INSERT INTO primary_keyTest Value(1, 'LiuYi', 18), (2, 'ChenEr', 20);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0mysql> SELECT * FROM primary_keyTest;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | LiuYi | 18 |
| 2 | ChenEr | 20 |
+----+--------+------+
2 rows in set (0.00 sec)mysql> INSERT INTO primary_keyTest VALUES(1, 'insert fail', NULL);
ERROR 1062 (23000): Duplicate entry '1' for key 'primary_keyTest.PRIMARY'
通常情况下设置PRIMARY KEY
主键后会为对应的column
设置NOT NULL
非空约束;
-
删除主键约束
主键约束通为表级约束, 因此删除主键约束时采用的是
ALTER TABLE table_name DROP PRIMARY KEY
;mysql> ALTER TABLE primary_keyTest DROP PRIMARY KEY; Query OK, 2 rows affected (0.04 sec) Records: 2 Duplicates: 0 Warnings: 0mysql> DESC primary_keyTest; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | bigint | NO | | NULL | | | name | varchar(20) | YES | | NULL | | | age | int | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 3 rows in set (0.01 sec)mysql>
-
增加主键约束
增加主键约束的方式可以使用
ALTER TABLE MODIFY/CHANGE/ADD PRIMARY KEY()
的方式进行增加;-
MODIFY
mysql> DESC primary_keyTest; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | bigint | NO | | NULL | | | name | varchar(20) | YES | | NULL | | | age | int | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 3 rows in set (0.01 sec)mysql> ALTER TABLE primary_keyTest MODIFY id BIGINT PRIMARY KEY; Query OK, 0 rows affected (0.04 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> DESC primary_keyTest; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | bigint | NO | PRI | NULL | | | name | varchar(20) | YES | | NULL | | | age | int | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec)
-
CHANGE
mysql> DESC primary_keyTest; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | bigint | NO | | NULL | | | name | varchar(20) | YES | | NULL | | | age | int | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec)mysql> ALTER TABLE primary_keyTest CHANGE id id BIGINT PRIMARY KEY; Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> DESC primary_keyTest; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | bigint | NO | PRI | NULL | | | name | varchar(20) | YES | | NULL | | | age | int | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec)
-
ADD PRIMARY KEY(column_name)
mysql> DESC primary_keyTest; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | bigint | NO | | NULL | | | name | varchar(20) | YES | | NULL | | | age | int | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec)mysql> ALTER TABLE primary_keyTest ADD PRIMARY KEY(id); Query OK, 0 rows affected (0.04 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> DESC primary_keyTest; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | bigint | NO | PRI | NULL | | | name | varchar(20) | YES | | NULL | | | age | int | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec)
-
复合主键
一张表内只能拥有一个主键, 但是主键是表级约束, 因此这意味着一张表的主键不单纯只能给一个列进行使用;
当一个主键被多个列使用时这个主键被称为复合主键;
mysql> CREATE TABLE compositePrimaryKeyTest(-> id BIGINT,-> name VARCHAR(20),-> age TINYINT,-> PRIMARY KEY(id, name)-> );
Query OK, 0 rows affected (0.02 sec)mysql> DESC compositePrimaryKeyTest;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | bigint | NO | PRI | NULL | |
| name | varchar(20) | NO | PRI | NULL | |
| age | tinyint | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
复合主键的作用和主键作用类似, 主要作为唯一性的标识, 与之不同的是与单主键不同, 单主键是将一个column
作为唯一值, 而复合主键则将多个columns
组合作为一个唯一值;
mysql> DESC compositePrimaryKeyTest;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | bigint | NO | PRI | NULL | |
| name | varchar(20) | NO | PRI | NULL | |
| age | tinyint | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)mysql> INSERT INTO compositePrimaryKeyTest VALUES(1, 'LiuYi', 18);
Query OK, 1 row affected (0.00 sec)mysql> INSERT INTO compositePrimaryKeyTest VALUES(1, 'ChenEr', 18);
Query OK, 1 row affected (0.00 sec)mysql> INSERT INTO compositePrimaryKeyTest VALUES(2, 'ChenEr', 18);
Query OK, 1 row affected (0.00 sec)mysql> INSERT INTO compositePrimaryKeyTest VALUES(1, 'LiuYi', 18);
ERROR 1062 (23000): Duplicate entry '1-LiuYi' for key 'compositePrimaryKeyTest.PRIMARY'
mysql> SELECT * FROM compositePrimaryKeyTest;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | ChenEr | 18 |
| 1 | LiuYi | 18 |
| 2 | ChenEr | 18 |
+----+--------+------+
3 rows in set (0.01 sec)
从结果可以看出, 虽然主键被两个column
所用, 但是单个column
重复不影响数据的插入, 当所有使用主键的column
重复时才会插入失败;
当设置主键/复合主键时, 如果没有设置NOT NULL
, 那么会主动为主键/复合主键 设置NOT NULL
约束, 但是如果删除主键约束, 并不会删除NOT NULL
约束, 因为本质上的主键约束的设置的NOT NULL
是mysqld优化mysql
命令得到的, 真正的主键设置规范格式就是得带NOT NULL
的, 而删除主键时不代表要删除NOT NULL
, 因此在删除主键时不会删除NOT NULL
约束;
-
复合主键的删除
复合主键的删除与主键一致(本质上就是主键);
-
复合主键的追加
通常采用
ADD PRIMARY KEY(column1, column2)
的方式进行追加;mysql> ALTER TABLE compositePrimaryKeyTest DROP PRIMARY KEY; Query OK, 3 rows affected (0.05 sec) Records: 3 Duplicates: 0 Warnings: 0mysql> DESC compositePrimaryKeyTest; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | bigint | NO | | NULL | | | name | varchar(20) | NO | | NULL | | | age | tinyint | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec)mysql> ALTER TABLE compositePrimaryKeyTest ADD PRIMARY KEY(id, name); Query OK, 0 rows affected (0.04 sec) Records: 0 Duplicates: 0 Warnings: 0mysql> DESC compositePrimaryKeyTest; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | bigint | NO | PRI | NULL | | | name | varchar(20) | NO | PRI | NULL | | | age | tinyint | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec)
auto_increment 自增长约束
auto_increament
自增长约束具体的作用是, 当表内某个column
为自增长, 但在插入时未给这个列插入数据时将会触发自增长;
通常情况下auto_increment
的约束所设置的colume
必须是KEY
或是索引, 否则无法增加, 其次一个表内最多只能有一个auto_increment
;
mysql> CREATE TABLE auto_incrementTest(-> id INT PRIMARY KEY AUTO_INCREMENT,-> name VARCHAR(20)-> );
Query OK, 0 rows affected (0.03 sec)mysql> DESC auto_incrementTest;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)mysql> INSERT INTO auto_incrementTest(name) VALUES('LiuYi');
Query OK, 1 row affected (0.00 sec)mysql> SELECT * FROM auto_incrementTest;
+----+-------+
| id | name |
+----+-------+
| 1 | LiuYi |
+----+-------+
1 row in set (0.00 sec)
同时主键自增约束实际上对自增的column
有排序的效果, 即对auto_increment
部分插入多组大小不同的数据, 数据会自动排序, 当自增主键的column
中的数据不连续后再次进行插入数据, 自增的部分将会由当前最大的值开始自增;
mysql> SELECT * FROM auto_incrementTest;
+----+-------+
| id | name |
+----+-------+
| 1 | LiuYi |
+----+-------+
1 row in set (0.00 sec)mysql> INSERT INTO auto_incrementTest VALUES(100, 'LiuYi');
Query OK, 1 row affected (0.00 sec)mysql> INSERT INTO auto_incrementTest VALUES(4, 'LiuYi');
Query OK, 1 row affected (0.05 sec)mysql> INSERT INTO auto_incrementTest(name) VALUES('ChenEr');
Query OK, 1 row affected (0.01 sec)mysql> SELECT * FROM auto_incrementTest;
+-----+--------+
| id | name |
+-----+--------+
| 1 | LiuYi |
| 4 | LiuYi |
| 100 | LiuYi |
| 101 | ChenEr |
+-----+--------+
4 rows in set (0.00 sec)
当然自增主键可以设置AUTO_INCREMENT
的下一个值(只能设置大于当前最大值的值才能有效);
mysql> SELECT * FROM auto_incrementTest;
+-----+--------+
| id | name |
+-----+--------+
| 1 | LiuYi |
| 4 | LiuYi |
| 100 | LiuYi |
| 101 | ChenEr |
+-----+--------+
4 rows in set (0.00 sec)mysql> ALTER TABLE auto_incrementTest AUTO_INCREMENT=5;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> INSERT INTO auto_incrementTest(name) VALUES('ZhangSan');
Query OK, 1 row affected (0.01 sec)mysql> SELECT * FROM auto_incrementTest;
+-----+----------+
| id | name |
+-----+----------+
| 1 | LiuYi |
| 4 | LiuYi |
| 100 | LiuYi |
| 101 | ChenEr |
| 102 | ZhangSan |
+-----+----------+
5 rows in set (0.00 sec)mysql> ALTER TABLE auto_incrementTest AUTO_INCREMENT=188;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0mysql> INSERT INTO auto_incrementTest(name) VALUES('LiSi');
Query OK, 1 row affected (0.01 sec)mysql> SELECT * FROM auto_incrementTest;
+-----+----------+
| id | name |
+-----+----------+
| 1 | LiuYi |
| 4 | LiuYi |
| 100 | LiuYi |
| 101 | ChenEr |
| 102 | ZhangSan |
| 188 | LiSi |
+-----+----------+
6 rows in set (0.00 sec)
将表数据清除后并不会重置AUTO_INCREMENT
;
mysql> SELECT * FROM auto_incrementTest;
+-----+----------+
| id | name |
+-----+----------+
| 1 | LiuYi |
| 4 | LiuYi |
| 100 | LiuYi |
| 101 | ChenEr |
| 102 | ZhangSan |
| 188 | LiSi |
+-----+----------+
6 rows in set (0.00 sec)mysql> DELETE FROM auto_incrementTest;
Query OK, 6 rows affected (0.01 sec)mysql>
mysql> SELECT * FROM auto_incrementTest;
Empty set (0.00 sec)mysql> INSERT INTO auto_incrementTest(name) VALUES('LiuYi'), ('ChenEr');
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0mysql> SELECt * FROM auto_incrementTest;
+-----+--------+
| id | name |
+-----+--------+
| 189 | LiuYi |
| 190 | ChenEr |
+-----+--------+
2 rows in set (0.00 sec)
需要手动删除表后并通过ALTER TABLE
来将该参数进行重置, 通常情况下AUTO_INCREMENT
的最小值为1
;
mysql> SELECt * FROM auto_incrementTest;
+-----+--------+
| id | name |
+-----+--------+
| 189 | LiuYi |
| 190 | ChenEr |
+-----+--------+
2 rows in set (0.00 sec)mysql> DELETE FROM auto_incrementTest;
Query OK, 2 rows affected (0.01 sec)mysql> SHOW CREATE TABLE auto_incrementTest\G
*************************** 1. row ***************************Table: auto_incrementTest
Create Table: CREATE TABLE `auto_incrementTest` (`id` int NOT NULL AUTO_INCREMENT,`name` varchar(20) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
唯一键
唯一键Unique
, 通常是用来保障数据唯一性的, 通常情况下唯一键与主键PRIMARY KEY
的使用场景不同;
-
PRIMARY KEY
主键约束主键约束主要的特性有:
- 唯一性
- 不可为空性
- 一张表里只能拥有一个
PRIMARY KEY
通常主键用于作为某条消息的唯一标识, 例如每个人的个人身份证;
-
UNIQUE
唯一键唯一键主要特性为如下:
-
唯一性
-
可空性
在部分
SQL
数据库中, 唯一键可有多个NULL
值数据同时存在(NULL
不参与唯一性比较); -
一张表里允许表内存在多个
UNIQUE
唯一键
唯一键通常是在业务上保证某个数据的唯一性以防止不与其他信息产生冲突, 如不同人的个人电话号码;
-
通常唯一键与主键属于互相补充;
-
场景演示
-
使用唯一键
mysql> create table if not exists stu1(-> id char(20) primary key not null,-> name varchar(10) not null comment ' 姓名不可为空',-> age int not null comment ' 年龄 不可为空',-> tel varchar(11) unique comment '电话 唯一键'-> ); Query OK, 0 rows affected (0.04 sec)mysql> insert into stu1 values('0001', 'LiuYi', '18', '13812345678'); Query OK, 1 row affected (0.01 sec)mysql> insert into stu1 values('0002', 'ChenEr', '18', '13812345679'); Query OK, 1 row affected (0.00 sec)mysql> insert into stu1 values('0003', 'ZhangSan', '18', NULL); Query OK, 1 row affected (0.01 sec)mysql> insert into stu1 values('0004', 'LiSi', '18', NULL); Query OK, 1 row affected (0.01 sec)mysql> select * from stu1; +------+----------+-----+-------------+ | id | name | age | tel | +------+----------+-----+-------------+ | 0001 | LiuYi | 18 | 13812345678 | | 0002 | ChenEr | 18 | 13812345679 | | 0003 | ZhangSan | 18 | NULL | | 0004 | LiSi | 18 | NULL | +------+----------+-----+-------------+ 4 rows in set (0.00 sec)mysql> select name from stu1 where tel='13812345679'; +--------+ | name | +--------+ | ChenEr | +--------+ 1 row in set (0.00 sec)
在这个例子中,
tel
列使用了唯一键, 能够保证数据唯一性; -
不使用唯一键
mysql> create table if not exists stu2(-> id char(20) primary key not null,-> name varchar(10) not null comment '姓名 不可为空',-> age int not null comment '年龄 不可为空',-> tel varchar(11) comment '电话 不使用唯一键'-> ); Query OK, 0 rows affected (0.03 sec)mysql> insert into stu2 values-> ('0001', 'LiuYi', '18', '13812345678'),-> ('0002', 'ChenEr', '18', '13812345679'),-> ('0003', 'ZhangSan', '18', '13812345679'); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0mysql> select * from stu2; +------+----------+-----+-------------+ | id | name | age | tel | +------+----------+-----+-------------+ | 0001 | LiuYi | 18 | 13812345678 | | 0002 | ChenEr | 18 | 13812345679 | | 0003 | ZhangSan | 18 | 13812345679 | +------+----------+-----+-------------+ 3 rows in set (0.00 sec)mysql> select name from stu2 where tel='13812345679'; +----------+ | name | +----------+ | ChenEr | | ZhangSan | +----------+ 2 rows in set (0.00 sec)
未使用唯一键, 因此无法找到
tel
列中值为13812345679
的唯一项;
通过唯一键
UNIQUE
/UNIQUE KEY
的唯一属性约束插入数据的用户对部分列进行数据插入时不能插入重复数据; -
外键约束
上述中提到的约束通常都是表中的约束, 而外键约束则是针对表与表之间的约束, 即定义父表与子表(主表与从表)之间的关系;
-
父表(主表)
通常为被引用的表, 包含主键或是唯一键;
父表是数据的"源"或"提供者", 其某列(主键或唯一键)会被其他表引用;
-
子表(从表)
引用父表数据的表, 该表中的某个列会指向父表的主键或唯一键, 这个指向关系即为外键约束, 子表的外键确保了引用的数据的有效性;
mysql> create table if not exists students(-> student_id int primary key comment '学生id',-> student_name varchar(15)-> );
Query OK, 0 rows affected (0.02 sec)mysql> create table if not exists courses(-> course_id int primary key,-> course_name varchar(20),-> student_id int,-> foreign key (student_id) references students(student_id)-> );
Query OK, 0 rows affected (0.04 sec)mysql> desc students;
+--------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| student_id | int | NO | PRI | NULL | |
| student_name | varchar(15) | YES | | NULL | |
+--------------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)mysql> desc courses;
+-------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+-------+
| course_id | int | NO | PRI | NULL | |
| course_name | varchar(20) | YES | | NULL | |
| student_id | int | YES | MUL | NULL | |
+-------------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)mysql> show create table courses\G
*************************** 1. row ***************************Table: courses
Create Table: CREATE TABLE `courses` (`course_id` int NOT NULL,`course_name` varchar(20) DEFAULT NULL,`student_id` int DEFAULT NULL,PRIMARY KEY (`course_id`),KEY `student_id` (`student_id`),CONSTRAINT `courses_ibfk_1` FOREIGN KEY (`student_id`) REFERENCES `students` (`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
这是一个学生表和选修课程表的外键关系演示, 其中学生表students
为父表, 课程表courses
为子表;
-
父子表的关系
-
关联关系
当存在一对存在外键关系的父子表时, 可以对子表进行数据插入, 当外键列传入数据不为空时, 该外键列数据必须在引用父表的主键/唯一键列中存在数据,否则将会插入失败;
mysql> desc courses; +-------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+-------------+------+-----+---------+-------+ | course_id | int | NO | PRI | NULL | | | course_name | varchar(20) | YES | | NULL | | | student_id | int | YES | MUL | NULL | | +-------------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec)mysql> desc students; +--------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------------+-------------+------+-----+---------+-------+ | student_id | int | NO | PRI | NULL | | | student_name | varchar(15) | YES | | NULL | | +--------------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec)mysql> select * from students; Empty set (0.00 sec)mysql> insert into courses values (13, 'math', 12); ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`student`.`courses`, CONSTRAINT `courses_ibfk_1` FOREIGN KEY (`student_id`) REFERENCES `students` (`student_id`))
-
非强制关系
通常情况下, 在
MySQL
中父表中的主键或唯一键可以与子表的外键产生关联关系, 但这个关联关系通常不是强制需求的,通常取决于业务逻辑;当存在外键, 子表进行数据插入时, 数据可以不传入外键列的数据, 即对子表进行数据插入时, 外键列可以为空(外键列未设置
NOT NULL
非空约束时);mysql> desc courses; +-------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+-------------+------+-----+---------+-------+ | course_id | int | NO | PRI | NULL | | | course_name | varchar(20) | YES | | NULL | | | student_id | int | YES | MUL | NULL | | +-------------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec)mysql> insert into courses(course_id, course_name) values(12, "hello"); Query OK, 1 row affected (0.01 sec)mysql> select * from courses; +-----------+-------------+------------+ | course_id | course_name | student_id | +-----------+-------------+------------+ | 12 | hello | NULL | +-----------+-------------+------------+ 1 row in set (0.00 sec)
本次对子表进行数据插入时进行选择列插入, 未对外键列
student_id
进行插入, 该列为空, 可正常插入数据;这种非强制关系可以使得数据在进行管理时可以根据业务需求进行灵活调整, 下面有两个例子可以解释外键列可为空与外键列设置非空属性的两种简单业务场景;
-
强制关联关系(外键列设置非空约束)
订单与订单明细 存在两张表:
- 订单表
- 订单明细表
CREATE TABLE customers (id INT PRIMARY KEY,name VARCHAR(50) );CREATE TABLE orders (id INT PRIMARY KEY,order_date DATE,customer_id INT NOT NULL,FOREIGN KEY (customer_id) REFERENCES customers(id) );
通常情况下订单将会存在一个
id
作为每个订单的唯一标识;而订单的订单明细则对订单中的其他数据进行存储, 同样需要存在一个
id
,而订单明细中的这个id
需要存在两个属性:- 与订单相关联
- 是订单明细的唯一标识
在这种需求下, 又因为订单与订单明细的先后关系为"先有订单, 后又明细";
因此订单的
id
将被订单明细所给引用, 订单明细表中的id
将作为外键列, 引用订单的id
;这种情况下, 父表与子表存在强制关联关系, 即子表记录必须依赖父表存在, 关系是强制的;
- 业务场景
- 每个订单明细必须属于一个有效订单
- 数据完整性要求严格, 不能存在"孤儿"记录
- 业务逻辑上明细脱离订单无意义
-
非强制关联关系(外键列未设置非空约束)
员工与部门 存在两张表:
- 员工表
- 部门表
CREATE TABLE departments (id INT PRIMARY KEY,name VARCHAR(50) );CREATE TABLE employees (id INT PRIMARY KEY,name VARCHAR(50),department_id INT,FOREIGN KEY (department_id) REFERENCES departments(id) );
在子表中,
department_id
并为设置非空约束NOT NULL
,即非强制关联关系, 这意味这该外键列可插入空属性;本质是因为当入职一个员工时, 入职的员工将出现不同的状态, 通常的状态存在:
- 已分配部门
- 未分配部门
对于父表与子表是否需要进行强制关联本质上取决于业务需求;
-
-
如何判断父子表
通常情况下载设置外键约束前需要判断两张表的父子关系;
通常可以采用问题清单的方式来判断父子关系;
同样采用上文的例子进行举例(员工 - 部门, 学生 - 班级)
- 哪个实体可以独立存在
- 部门可以没有员工 √
- 员工可以没有部门 × (某些设计中允许)
- 数据创建顺序
- 先有部门后又员工
- 先有班级后有学生
- 删除时的级联影响
- 删除部门是否影响员工/删除员工是否影响部门
- 删除班级是否影响学生/删除学生是否影响班级
- 业务语义关系
- 班级"包含"学生, 学生"属于"班级
- 部门"拥有"员工, 员工"属于"部门
综合例题
有一个商店的数据,记录客户及购物情况,有以下三个表组成:
- 商品 goods (商品编号 goods_id,商品名 goods_name, 单价 unitprice, 商品类别 category,供应商 provider)
- 客户 customer (客户号 customer_id, 姓名 name, 住址 address, 邮箱 email, 性别 sex,身份证 card_id)
- 购买 purchase (购买订单号 order_id, 客户号 customer_id, 商品号 goods_id, 购买数量 nums)
要求:
- 每个表的主外键
- 客户的姓名不能为空值
- 邮箱不能重复
- 客户的性别 (男,女)
mysql> show create table customer\G
*************************** 1. row ***************************Table: customer
Create Table: CREATE TABLE `customer` (`customer_id` char(20) NOT NULL COMMENT '客户号',`name` varchar(10) NOT NULL COMMENT '客户姓名',`address` varchar(100) DEFAULT NULL COMMENT '住址',`email` varchar(50) DEFAULT NULL COMMENT ' 用户邮箱',`sex` enum('man','woman') DEFAULT NULL COMMENT '用户性别',`card_id` varchar(18) DEFAULT NULL COMMENT '身份证',PRIMARY KEY (`customer_id`),UNIQUE KEY `email` (`email`),UNIQUE KEY `card_id` (`card_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)mysql> show create table goods\G
*************************** 1. row ***************************Table: goods
Create Table: CREATE TABLE `goods` (`goods_id` char(20) NOT NULL COMMENT '商品编号',`goods_name` varchar(50) DEFAULT NULL COMMENT '商品名',`unitprice` decimal(10, 2) DEFAULT NULL COMMENT '商品价格',`category` varchar(10) DEFAULT NULL COMMENT '商品类别',`provider` varchar(15) DEFAULT NULL COMMENT '供应商',PRIMARY KEY (`goods_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)mysql> show create table purchase\G
*************************** 1. row ***************************Table: purchase
Create Table: CREATE TABLE `purchase` (`order_id` varchar(18) NOT NULL COMMENT '购买订单号',`customer_id` char(20) DEFAULT NULL COMMENT '客户号 - 外键',`goods_id` char(20) DEFAULT NULL COMMENT '商品号 - 外键',`nums` int unsigned DEFAULT NULL COMMENT '购买数量',PRIMARY KEY (`order_id`),KEY `customer_id` (`customer_id`),KEY `goods_id` (`goods_id`),CONSTRAINT `purchase_ibfk_1` FOREIGN KEY (`customer_id`) REFERENCES `customer` (`customer_id`),CONSTRAINT `purchase_ibfk_2` FOREIGN KEY (`goods_id`) REFERENCES `goods` (`goods_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.01 sec)