当前位置: 首页 > news >正文

mysql 表的约束

目录

mysql 表的约束

NULL/NOT NULL

DEFAULT

comment

zerofill

PRIMARY KRY

删除主键

添加主键

复合主键

AUTO_INCREMENT

UNIQUE KEY

FOREIGN KEY


mysql 表的约束

约束是 mysql 为了保证数据正确的一种手段,而前面在谈数据类型的时候,数据类型其实就是一种约束,但是 mysql 的约束可不仅仅是数据类型,mysql 有各种各样的约束,下面就看一下 mysql 中其他的约束。

NULL/NOT NULL

null / not null 约束是mysql常见的一种约束之一,not null,可以保证用户输入的数据不为空。

创建一张表,里面添加 not null 约束:

mysql> use restraint;
Database changed
mysql> create table t1(-> name varchar(12),-> age tinyint not null);
Query OK, 0 rows affected (0.01 sec)
​
mysql> desc t1;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name  | varchar(12) | YES  |     | NULL    |       |
| age   | tinyint(4)  | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

这里表已经创建好了,其中 name 并没有设置约束,而age 设置了 not null 约束,通过 desc 查看表结构发现在 Null 那一列发现 name 的 Null 列显示 yes 表示可以为 null ,但是 age 显示 No 表示不能为空。

插入数据测试 not null 约束:

mysql> insert into t1(name, age) values('张三', 27);
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into t1(age) values(27);
Query OK, 1 row affected (0.00 sec)
​
mysql> select * from t1;
+--------+-----+
| name   | age |
+--------+-----+
| 张三   |  27 |
| NULL   |  27 |
+--------+-----+
2 rows in set (0.00 sec)

上面使用全列插入,还有只插入了 age 发现插入成功,但是只插入了 age 的那一条记录发现name为 NULL。

不插入age 和 插入 age 为NULL 测试:

mysql> insert into t1(name) values(27);
ERROR 1364 (HY000): Field 'age' doesn't have a default value
mysql> insert into t1(name,age) values(27, null);
ERROR 1048 (23000): Column 'age' cannot be null

上面两条记录均插入失败,但是仔细观察发现这两条记录插入的报错信息却是不一样的,没有插入 age 的那条报错显示没有默认的 value 但是插入为 null 的报错信息显示不能为 null。

其实这里发现 not null 约束和 default 约束还有一点点联系,下面看 default 约束会让两者进行对比。

DEFAULT

default 约束就是在填表的时候可以直接忽略掉该列,然后可以让 default 默认填写,但是如果插入了数据,就会按照插入的数据来看。

下面通过查看表创建来看一下 default 和 not null。

创建一张表,里面有 id 为 int 类型且无约束,name varchar(12) 为 not null 还有 age tinyint 为 default 22:

mysql> create table t2(-> id int,-> name varchar(12) not null,-> age tinyint default '22');
Query OK, 0 rows affected (0.00 sec)
​
mysql> desc t2;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(12) | NO   |     | NULL    |       |
| age   | tinyint(4)  | YES  |     | 22      |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

这里创建成功,同时也看到 Null 里面 name 不为空,default 里面 age 默认为 22,和我们设置的一样。

下面在看一下表的创建sql语句:

mysql> show create table t2 \G
*************************** 1. row ***************************Table: t2
Create Table: CREATE TABLE `t2` (`id` int(11) DEFAULT NULL,`name` varchar(12) NOT NULL,`age` tinyint(4) DEFAULT '22'
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql 通过语法分析词法分析以及各种优化等,帮我们记录的该表创建sql语句就是这样的,而 id 里面在我们写的时候并没有添加 default 但是mysql自动帮我们添加 default null。

插入数据:

mysql> insert into t2(id, name, age) values(1, '张三', 10);
Query OK, 1 row affected (0.01 sec)
​
mysql> insert into t2(name, age) values('张三', 10);
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into t2(name) values('张三');
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into t2(name, age) values('张三', NULL);
Query OK, 1 row affected (0.00 sec)
​
mysql> select * from t2;
+------+--------+------+
| id   | name   | age  |
+------+--------+------+
|    1 | 张三   |   10 |
| NULL | 张三   |   10 |
| NULL | 张三   |   22 |
| NULL | 张三   | NULL |
+------+--------+------+
4 rows in set (0.00 sec)

这里分别是全列插入,不插入 id ,不插入 id 和 age,不插入 id 且插入 age 为 NULL,上面发现均插入成功,且而没有插入 id 则 id 均为 null,就是像上面的sql 创建语句一样 id 默认为 null,而没有插入 age ,age就是默认 22,还有就是插入 age 为 NULL 也插入成功。

那么通过上面的测试,现在假设我们将一列字段的约束设置为即有 not null 约束,也有 default 约束会怎么样:

mysql> create table t3(-> id int not null,-> name varchar(12) default '张三',-> age tinyint not null default 20);
Query OK, 0 rows affected (0.01 sec)
​
mysql> desc t3;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| name  | varchar(12) | YES  |     | 张三    |       |
| age   | tinyint(4)  | NO   |     | 20      |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
​
mysql> show create table t3\G
*************************** 1. row ***************************Table: t3
Create Table: CREATE TABLE `t3` (`id` int(11) NOT NULL,`name` varchar(12) DEFAULT '张三',`age` tinyint(4) NOT NULL DEFAULT '20'
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

创建完成后,现在我们就是很好奇向 age 里面插入数据,或者直接忽略此字段会怎么样?

mysql> insert into t3(id, name, age) values(1, '田七', 12);
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into t3(id, name) values(1, '田七');
Query OK, 1 row affected (0.00 sec)
​
mysql> select * from t3;
+----+--------+-----+
| id | name   | age |
+----+--------+-----+
|  1 | 田七   |  12 |
|  1 | 田七   |  20 |
+----+--------+-----+
2 rows in set (0.01 sec)

上面的插入均成功了,即使忽略了也可以默认,那么下面我们插入 NULL 呢?

mysql> insert into t3(id, name, age) values(1, '田七', NULL);
ERROR 1048 (23000): Column 'age' cannot be null

这里插入失败了,通过上面的测试,我们发现了 not null 和 default 的区别:

  • default 约束的是用户不插入数据的时候

  • not null 约束的是用户插入数据的时候

comment

comment 其实并不是用来约束数据插入的,而在我认为他就是一种软约束,它约束的是用户看到 comment 的时候就知道该列里面填入的数据是何种类型或者样式。

comment 其实在数据类型的时候就以及用过了,而且该约束还是比较简答的。

mysql> create  table t4(-> name varchar(12) comment '用户名',-> age tinyint comment '用户年龄');
Query OK, 0 rows affected (0.01 sec)
​
mysql> desc t4;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name  | varchar(12) | YES  |     | NULL    |       |
| age   | tinyint(4)  | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

表创建好后,并不能用 desc 查看到该约束,想要查看该约束还是需要用查看该表创建时的sql语句:

mysql> show create table t4\G
*************************** 1. row ***************************Table: t4
Create Table: CREATE TABLE `t4` (`name` varchar(12) DEFAULT NULL COMMENT '用户名',`age` tinyint(4) DEFAULT NULL COMMENT '用户年龄'
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

zerofill

zerofill 该约束其实时用在整数类型的,之前在创建 int 类型的时候后面总是会带一个括号里面写着 11,其实该约束和那个括号就有关系,而且该约束时显示约束,并不会对用户插入数据等有影响,只是在显示的时候会有不同的样子。

mysql> create table t5(-> num int zerofill);
Query OK, 0 rows affected (0.01 sec)
​
mysql> desc t5;
+-------+---------------------------+------+-----+---------+-------+
| Field | Type                      | Null | Key | Default | Extra |
+-------+---------------------------+------+-----+---------+-------+
| num   | int(10) unsigned zerofill | YES  |     | NULL    |       |
+-------+---------------------------+------+-----+---------+-------+
1 row in set (0.00 sec)

这里看到确实添加了 zero fill 并且默认给我们添加了 unsigned 下面插入数据查看我们就知道了:

mysql> insert into t5 values(1);
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into t5 values(11);
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into t5 values(111);
Query OK, 1 row affected (0.00 sec)
​
mysql> select * from t5;
+------------+
| num        |
+------------+
| 0000000001 |
| 0000000011 |
| 0000000111 |
+------------+
3 rows in set (0.00 sec)

这里发现插入后,这些数字前面均加了一下 0 这个就是 zerofill 的显示约束而且 int 后面的那个数字就表示可以显示多少位数字,如果是有符号整型,那么就是 11 位,如果是无符号就是 10位,我们也可以改变该 int 后面的数字来查看:

mysql> alter table t5 modify num int(4) zerofill;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0
​
mysql> desc t5;
+-------+--------------------------+------+-----+---------+-------+
| Field | Type                     | Null | Key | Default | Extra |
+-------+--------------------------+------+-----+---------+-------+
| num   | int(4) unsigned zerofill | YES  |     | NULL    |       |
+-------+--------------------------+------+-----+---------+-------+
1 row in set (0.00 sec)

修改完成后继续查看插入后的数据:

mysql> select * from t5;
+------+
| num  |
+------+
| 0001 |
| 0011 |
| 0111 |
+------+
3 rows in set (0.00 sec)

现在就变成 最高显示4位的整数了,而 zerofill 就是帮助如果没有超出该显示范围就用 0 来补充。

下面插入一个大于 4 位数的数据:

mysql> select * from t5;
+--------+
| num    |
+--------+
|   0001 |
|   0011 |
|   0111 |
| 111111 |
+--------+
4 rows in set (0.00 sec)

这里发现如果超出的话就是正常显示,也不会发生截断。

PRIMARY KRY

主键约束,在一张表里面只能有一个主键,而且主键不能为空且不能重复,下面看一下如何设置主键:

mysql> create table t6(-> id int primary key,-> name varchar(12) not null,-> age tinyint default 18-> );
Query OK, 0 rows affected (0.01 sec)
​
mysql> desc t6;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(12) | NO   |     | NULL    |       |
| age   | tinyint(4)  | YES  |     | 18      |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

设置 id 为主键后, Null 列显示 id 不能为空,且 key 列 显示为 pri 也就是 primary key 主键,默认为空。

插入数据:

mysql> insert into t6(id, name, age) values(1, '天蓬元帅', 28);
Query OK, 1 row affected (0.01 sec)
​
mysql> insert into t6(id, name, age) values(2, '玉皇大帝', 106);
Query OK, 1 row affected (0.01 sec)
​
mysql> select  * from t6;
+----+--------------+------+
| id | name         | age  |
+----+--------------+------+
|  1 | 天蓬元帅      |   28 |
|  2 | 玉皇大帝      |  106 |
+----+--------------+------+
2 rows in set (0.00 sec)
​

这里插入 id 分别为 1 和 2 显示插入成功,查询数据同样显示插入成功,下面插入相同的 id 查看是否可以插入:

mysql> insert into t6(id, name, age) values(2, '女儿国王', 18);
ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'

这里显示插入失败了,报错原因就是已经有主键了。

那么如果我们直接省略掉该列看一下:

mysql> insert into t6(name, age) values('东海龙王', 18);
ERROR 1364 (HY000): Field 'id' doesn't have a default value

由于主键也是不能为空,所以也不能插入。

那么如果表已经创建好了,但是还想为其插入主键怎么办?

删除主键

alter table table_name drop primary key;

因为只有一个主键,所以删除可以直接 drop primary key。

mysql> alter table t6 drop primary key;
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0
​
mysql> desc t6;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| name  | varchar(12) | NO   |     | NULL    |       |
| age   | tinyint(4)  | YES  |     | 18      |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

这里看到删除成功了。

删除主键后,我们继续插入相同的 id 看是否能插入:

mysql> insert into t6(id, name, age) values(2, '女儿国王', 18);
Query OK, 1 row affected (0.00 sec)
​
mysql> select * from t6;
+----+--------------+------+
| id | name         | age  |
+----+--------------+------+
|  1 | 天蓬元帅      |   28 |
|  2 | 玉皇大帝      |  106 |
|  2 | 女儿国王      |   18 |
+----+--------------+------+
3 rows in set (0.00 sec)

这里插入就直接成功了。

添加主键

alter table table_name add primary key(列名);
mysql> alter table t6 add primary key(id);
ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'

上面我们添加主键失败了,为什么?

因为我们在前面插入了相同的 id 所以为 id 添加主键就会失败,所以我们需要修改 id 不重复就好了:

mysql> update t6 set id=3 where name='女儿国王';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
​
mysql> select * from t6;
+----+--------------+------+
| id | name         | age  |
+----+--------------+------+
|  1 | 天蓬元帅      |   28 |
|  2 | 玉皇大帝      |  106 |
|  3 | 女儿国王      |   18 |
+----+--------------+------+
3 rows in set (0.00 sec)

修改成功后,我们继续添加主键:

mysql> alter table t6 add primary key(id);
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0
​
mysql> desc t6;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(12) | NO   |     | NULL    |       |
| age   | tinyint(4)  | YES  |     | 18      |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

这里添加主键再次成功,下面我们插入相同的 id 看一下:

mysql> insert into t6 (id, name, age) values(3, '东海龙王', 99);
ERROR 1062 (23000): Duplicate entry '3' for key 'PRIMARY'

这里插入相同数据后就失败了。

复合主键

复合主键就是多列共成主键,我们之前说的是主键只能有一个,但是一个主键既可以由一列构成,也可以由多列构成。

添加复合主键:

mysql> create table t7(-> student_id char(5),-> course_id  tinyint unsigned,-> primary key(student_id, course_id)-> );
Query OK, 0 rows affected (0.00 sec)
​
mysql> desc t7;
+------------+---------------------+------+-----+---------+-------+
| Field      | Type                | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+-------+
| student_id | char(5)             | NO   | PRI | NULL    |       |
| course_id  | tinyint(3) unsigned | NO   | PRI | NULL    |       |
+------------+---------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

这里看到设置了复合主键, key 列里面的两列都是 PRI,这里并不是两个都是主键,而是这两个形成一个主键。

看到上面的创建复合主键的方法,我们也就知道在添加一个主键的时候也可以这样写。

下面看一下这个复合主键是怎么样子的:

mysql> insert into t7(student_id, course_id) values('11111', 12);
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into t7(student_id, course_id) values('22222', 12);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t7;
+------------+-----------+
| student_id | course_id |
+------------+-----------+
| 11111      |        12 |
| 22222      |        12 |
+------------+-----------+
2 rows in set (0.00 sec)

这里看到我们插入 student_id 没有重复,但是 course_id 重复了,但是插入成功,下麦呢看一下 student_id 重复:

mysql> insert into t7(student_id, course_id) values('22222', 13);
Query OK, 1 row affected (0.00 sec)
​
mysql> select * from t7;
+------------+-----------+
| student_id | course_id |
+------------+-----------+
| 11111      |        12 |
| 22222      |        12 |
| 22222      |        13 |
+------------+-----------+
3 rows in set (0.00 sec)

下面我们插入了 student_id 重复,但是 course_id 不重复也插入成功了。

下面让 student_id 和 course_id 都重复:

mysql> insert into t7(student_id, course_id) values('22222', 13);
ERROR 1062 (23000): Duplicate entry '22222-13' for key 'PRIMARY'

这里插入相同的数据,显示报错了,这里看到复合主键将这些数据都连接在一起了,所以对于复合主键来说,如果都重复才算重复,只有其中一个重复,或者是都不重复就不算重复。

AUTO_INCREMENT

自增键,一般都是和主键共同使用,下面还是先直接看一下自增键的使用然后在得出结论。

mysql> create table t8(-> id int unsigned primary key auto_increment,-> name varchar(12) default '张三');
Query OK, 0 rows affected (0.01 sec)
​
mysql> desc t8;
+-------+------------------+------+-----+---------+----------------+
| Field | Type             | Null | Key | Default | Extra          |
+-------+------------------+------+-----+---------+----------------+
| id    | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| name  | varchar(12)      | YES  |     | 张三    |                |
+-------+------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

创建好后查看到该表的结构,一般自增都在一张表中只能由一个自增键,下面我们可以在创建一张表看一下是否可以由多个自增键:

mysql> create table t9(-> id1 primary key auto_increment,-> id2 auto_increment);
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'primary key auto_increment,
id2 auto_increment)' at line 2

这里就直接报错了,不能有多个自增键。

下面我们插入数据看一下:

mysql> insert into t8(name) values('张三');
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into t8(name) values('李四');
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into t8(name) values('王五');
Query OK, 1 row affected (0.00 sec)
​
mysql> select *from t8;
+----+--------+
| id | name   |
+----+--------+
|  1 | 张三   |
|  2 | 李四   |
|  3 | 王五   |
+----+--------+
3 rows in set (0.00 sec)
​

这里插入后,我们没有插入 id 但是 id 从1开始依次递增,那么我们主动插入 id:

mysql> insert into t8(id, name) values(1000, '赵六');
Query OK, 1 row affected (0.00 sec)
​
mysql> select * from t8;
+------+--------+
| id   | name   |
+------+--------+
|    1 | 张三   |
|    2 | 李四   |
|    3 | 王五   |
| 1000 | 赵六   |
+------+--------+
4 rows in set (0.00 sec)

这里主动插入后也成功了,那么我们继续忽略 id 列呢:

mysql> insert into t8(name) values('田七');
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into t8(name) values('王小二');
Query OK, 1 row affected (0.00 sec)
​
mysql> select * from t8;
+------+-----------+
| id   | name      |
+------+-----------+
|    1 | 张三      |
|    2 | 李四      |
|    3 | 王五      |
| 1000 | 赵六      |
| 1001 | 田七      |
| 1002 | 王小二    |
+------+-----------+
6 rows in set (0.00 sec)

这里看到插入的数据是从上一次的数据增加的,这里我们可以看一下该表的创建 sql 就知道了:

mysql> show create table t8\G
*************************** 1. row ***************************Table: t8
Create Table: CREATE TABLE `t8` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`name` varchar(12) DEFAULT '张三',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1003 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

这里创建 sql 里面底下有一句 auto_increment=1003,而且下一次插入的话确实是从 1003 开始,所以我们知道,我们也可以在创建的时候加这一句:

mysql> create  table t9(-> id int primary key auto_increment,-> name varchar(12) default '张三'-> )auto_increment=100;
Query OK, 0 rows affected (0.00 sec)
​
mysql> show create  table t9\G
*************************** 1. row ***************************Table: t9
Create Table: CREATE TABLE `t9` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(12) DEFAULT '张三',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

这里创建好后,看到自增就是从100开始,下面插入数据查看:

mysql> insert into t9(name) values('张三');
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into t9(name) values('李四');
Query OK, 1 row affected (0.01 sec)
​
mysql> insert into t9(name) values('王五');
Query OK, 1 row affected (0.00 sec)
​
mysql> select * from t9;
+-----+--------+
| id  | name   |
+-----+--------+
| 100 | 张三   |
| 101 | 李四   |
| 102 | 王五   |
+-----+--------+
3 rows in set (0.00 sec)

UNIQUE KEY

唯一键和主键很容易弄混,有时候不知道该使用主键还是唯一键,唯一键和主键功能上的区别并不大,只是主键不能为空,而唯一键可以为空。

唯一键不能重复,但是唯一键可以为空,但是如果设置唯一键后在设置一个 NOT NULL,那么就和主键的功能上没有区别了。

下面还是直接看一下唯一键,然后说一下唯一键和主键的意义上的区别。

mysql> create table tt1(-> id int primary key,-> telephone char(11) unique,-> name varchar(12));Query OK, 0 rows affected (0.00 sec)
​
mysql> desc tt1;
+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| id        | int(11)     | NO   | PRI | NULL    | auto_increment |
| telephone | char(11)    | YES  | UNI | NULL    |                |
| name      | varchar(12) | YES  |     | NULL    |                |
+-----------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

这里设置了一个自增,一个唯一键,下面插入数据:

mysql> insert into tt1(telephone, name) values('12345678901', '贾宝玉');
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into tt1(telephone, name) values('12345678902', '林黛玉');
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into tt1(telephone, name) values('12345678903', '王熙凤');
Query OK, 1 row affected (0.01 sec)
​
mysql> select * from tt1;
+----+-------------+-----------+
| id | telephone   | name      |
+----+-------------+-----------+
|  1 | 12345678901  | 贾宝玉    |
|  2 | 12345678902  | 林黛玉    |
|  3 | 12345678903  | 王熙凤    |
+----+-------------+-----------+
3 rows in set (0.01 sec)

这里插入数据成功了,那么下面插入telephone 重复数据:

mysql> insert into tt1(telephone, name) values('12345678903', '贾母');
ERROR 1062 (23000): Duplicate entry '12345678903' for key 'telephone'

这里插入重复 telephone 然后失败,这里的唯一键不能重复,那么能不能为空:

mysql> insert into tt1(telephone, name) values(NULL, '贾母');
Query OK, 1 row affected (0.00 sec)
​
mysql> select * from tt1;
+----+-------------+-----------+
| id | telephone   | name      |
+----+-------------+-----------+
|  1 | 12345678901  | 贾宝玉    |
|  2 | 12345678902  | 林黛玉    |
|  3 | 12345678903  | 王熙凤    |
|  5 | NULL         | 贾母      |
+----+-------------+-----------+
4 rows in set (0.00 sec)

这里插入 null 成功,所以唯一键可以为空,但是主键不能为空,那么为telephone添加not null 和主键还有没有区别:

mysql> alter table tt1 modify telephone char(11) not null unique;
ERROR 1138 (22004): Invalid use of NULL value

上面添加not null 失败为什么? 因为我们插入了贾母 telephone 为空,所以失败了,我们将该数据跟新:

mysql> update tt1 set telephone=12345678904 where id=5;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

跟新成功后下面重新添加 not null:

mysql> alter table tt1 modify telephone char(11) not null unique;
Query OK, 0 rows affected, 1 warning (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 1
​
mysql> desc tt1;
+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| id        | int(11)     | NO   | PRI | NULL    | auto_increment |
| telephone | char(11)    | NO   | UNI | NULL    |                |
| name      | varchar(12) | YES  |     | NULL    |                |
+-----------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)

这里修改成功了,然后我们在测试一下:

mysql> insert into tt1(telephone, name) values('12345678901', '薛宝钗');
ERROR 1062 (23000): Duplicate entry '12345678901' for key 'telephone'

上面插入重复数据失败,下面插入NULL:

mysql> insert into tt1(telephone, name) values(NULL, '薛宝钗');
ERROR 1048 (23000): Column 'telephone' cannot be null

这里插入 NULL 也失败了,现在到功能上讲和主键是没有区别的,但是这两个的意义却是不同的,其中主键是为了保证每一行记录的唯一性,而唯一键为了让逻辑更通顺,保证其他的值的唯一,但是其实主键还有索引,而唯一键没有。

FOREIGN KEY

外键约束,外键就是其他表的主键,一般从表里面的外键就来自于主表里面的主键,下面还是直接看一下外键。

下面直接创建两张表,其中学生表中存储的是学生 id name 和 class_id (班级号),class 表里面存的是班级 id 和班级名,学生表通过班级 id 和 班级表里面的班级 id 关联起来。

mysql> create table student(-> student_id char(5) primary key,-> name varchar(12) not null,-> class_id char(5));
Query OK, 0 rows affected (0.01 sec)
​
mysql> create table class(-> class_id char(5) primary key,-> class_name varchar(12));
Query OK, 0 rows affected (0.01 sec)
​
mysql> desc student;
+------------+-------------+------+-----+---------+-------+
| Field      | Type        | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| student_id | char(5)     | NO   | PRI | NULL    |       |
| name       | varchar(12) | NO   |     | NULL    |       |
| class_id   | char(5)     | YES  |     | NULL    |       |
+------------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
​
mysql> desc class;
+------------+-------------+------+-----+---------+-------+
| Field      | Type        | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| class_id   | char(5)     | NO   | PRI | NULL    |       |
| class_name | varchar(12) | YES  |     | NULL    |       |
+------------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

上面并没有通过外键关联起来。

下面插入数据:

mysql> insert into class values('22001', '物联网01班');
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into class values('22002', '物联网02班');
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into class values('22003', '计算机01班');
Query OK, 1 row affected (0.01 sec)
​
mysql> insert into student values('00001', '豹子头', '22001');
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into student values('00002', '黑旋风', '22001');
Query OK, 1 row affected (0.01 sec)
​
mysql> insert into student values('00003', '及时雨', '22002');
Query OK, 1 row affected (0.00 sec)
​
mysql> select * from class;
+----------+----------------+
| class_id | class_name     |
+----------+----------------+
| 22001    | 物联网01班     |
| 22002    | 物联网02班     |
| 22003    | 计算机01班     |
+----------+----------------+
3 rows in set (0.00 sec)
​
mysql> select * from student;
+------------+-----------+----------+
| student_id | name      | class_id |
+------------+-----------+----------+
| 00001      | 豹子头    | 22001    |
| 00002      | 黑旋风    | 22001    |
| 00003      | 及时雨    | 22002    |
+------------+-----------+----------+
3 rows in set (0.01 sec)

上面就是插入数据,那么我们继续插入数据:

mysql> insert into student values('00004', '智多星', '22006');
Query OK, 1 row affected (0.00 sec)
​
mysql> select * from student;
+------------+-----------+----------+
| student_id | name      | class_id |
+------------+-----------+----------+
| 00001      | 豹子头    | 22001    |
| 00002      | 黑旋风    | 22001    |
| 00003      | 及时雨    | 22002    |
| 00004      | 智多星    | 22006    |
+------------+-----------+----------+
4 rows in set (0.00 sec)

这里插入了一个 22006 但是班级表中没有这个班级,根据我们现实合理吗?显然不合理。

下面我们删除掉一个班级:

mysql> delete from class where class_id='22001';
Query OK, 1 row affected (0.00 sec)
​
mysql> select * from class;
+----------+----------------+
| class_id | class_name     |
+----------+----------------+
| 22002    | 物联网02班     |
| 22003    | 计算机01班     |
+----------+----------------+
2 rows in set (0.00 sec)

这里删除成功了,也是不合理,所以我们需要添加外键约束:

但是在添加之前,我们需要删掉从表(student) 表,然后重新创建

mysql> create table student(-> Sid char(5) primary key,-> name varchar(12) not null,-> id char(5),-> foreign key(id) references class(class_id)-> );
Query OK, 0 rows affected (0.01 sec)
​
mysql> desc student;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| Sid   | char(5)     | NO   | PRI | NULL    |       |
| name  | varchar(12) | NO   |     | NULL    |       |
| id    | char(5)     | YES  | MUL | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
​

这里创建成功,那么现在重新插入:

mysql> insert into student(Sid, name, id) values('00001', '王熙凤', '22001');
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into student(Sid, name, id) values('00002', '贾宝玉', '22002');
Query OK, 1 row affected (0.00 sec)
​
mysql> insert into student(Sid, name, id) values('00003', '贾母', '22003');
Query OK, 1 row affected (0.00 sec)
​
mysql> select * from student;
+-------+-----------+-------+
| Sid   | name      | id    |
+-------+-----------+-------+
| 00001 | 王熙凤    | 22001 |
| 00002 | 贾宝玉    | 22002 |
| 00003 | 贾母      | 22003 |
+-------+-----------+-------+
3 rows in set (0.00 sec)

这里插入成功了,那么下面插入班级表里面没有的班级:

mysql> insert into student(Sid, name, id) values('00004', '赵姨娘', '22004');
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`restraint`.`student`, CONSTRAINT `fk_class_id` FOREIGN KEY (`id`) REFERENCES `class` (`class_id`))

这里插入失败了,下面删除掉任意一个班级:

mysql> delete from class where class_id='22001';
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`restraint`.`student`, CONSTRAINT `fk_class_id` FOREIGN KEY (`id`) REFERENCES `class` (`class_id`))

上面两条语句都失败了,这就是外键约束的作用。

那么下面说一下我对外键约束的理解:

  • 表与表之间有关系,所以需要联系起来。

  • 但是只有联系没有用,还是需要约束,所以还有外键约束。

虽然外键约束时一个,但是外键约束是由联系和约束组成的。

相关文章:

mysql 表的约束

目录 mysql 表的约束 NULL/NOT NULL DEFAULT comment zerofill PRIMARY KRY 删除主键 添加主键 复合主键 AUTO_INCREMENT UNIQUE KEY FOREIGN KEY mysql 表的约束 约束是 mysql 为了保证数据正确的一种手段,而前面在谈数据类型的时候,数据类…...

认识Redis

1. 前置操作 以下内容基于CentOS 1.1. 安装 yum -y install redis 1.2. 启动 redis-server /etc/redis.conf & 1.3. 打开 redis-cli 1.4. 停止 redis-cli shutdown 1.5. 设置远程连接 修改 /etc/redis/redis.conf 修改 bind 127.0.0.1为 bind 0.0.0.0 1.6. 使用…...

同步、异步无障碍:Python异步装饰器指南

一、引言 Python异步开发已经非常流行了,一些主流的组件像MySQL、Redis、RabbitMQ等都提供了异步的客户端,再处理耗时的时候不会堵塞住主线程,不但可以提高并发能力,也能减少多线程带来的cpu上下文切换以及内存资源消耗。但在业务…...

CodeSite for .NET Crack

CodeSite for .NET Crack CodeSite for.NET与Visual Studio集成,通过实时查看器日志记录系统提供对代码执行的更深入了解,该系统有助于在本地或远程执行代码时快速查找问题。超越传统的断点调试,在应用程序继续运行时记录应用程序的执行&…...

基于IMX6ULLmini的linux裸机开发系列九:时钟控制模块

时钟控制模块 核心 4个层次配置芯片时钟 晶振时钟 PLL与PFD时钟 PLL选择时钟 根时钟/外设时钟 系统时钟来源 RTC时钟源:32.768KHz 系统时钟:24MHz,作为芯片的主晶振使用 PLL和PFD倍频时钟 7路锁相环电路(每个锁相环电路…...

【数据结构与算法】1. 绪论

1. 绪论 1.1 数据结构 1.1.1 数据结构的基本概念 1.1.2 数据结构的三要素 数据结构三要素: 逻辑结构 划分方法一: 线性结构:线性表、栈、队列、串非线性结构:树、图 划分方法二: 集合结构线性结构树形结构网状&…...

2023年京东儿童智能手表行业数据分析(京东销售数据分析)

儿童消费市场向来火爆,儿童智能手表作为能够实现定位导航,信息通讯,SOS求救,远程监听,智能防丢等多功能的智能可穿戴设备,能够通过较为精准的定位功能和安全防护能力保障儿童的安全,因而广受消费…...

数据结构(6)

2-3查找树 2-结点:含有一个键(及其对应的值)和两条链,左链接指向2-3树中的键都小于该结点,右链接指向的2-3树中的键都大于该结点。 3-结点:含有两个键(及其对应的值)和三条链,左链接指向的2-3树中的键都小于该结点&a…...

C++学习|CUDA安装和配置

CUDA安装和配置 Windows下安装CUDAVS项目配置CUDA Windows下安装CUDA 第一步:先看自己NIVIDIA显卡适合什么版本的CUDA。打开电脑的“NIVIDIA控制面板”->系统信息->组件。会看到我的显卡驱动最高支持的CUDA版本是11.4.56。 第二步:去CUDA官网&…...

3.若依前后端分离版开发用户自定义配置表格功能

一、背景 在项目上线测试的时候,关于同一个界面的表格,不同的用户会出现不同的字段排列需求,有些用户希望把A字段排在最前面,有些用户则希望A字段不显示。针对这种情况,开发一个表格自定义配置的功能,每个…...

【操作系统】24王道考研笔记——第三章 内存管理

第三章 内存管理 一、内存管理概念 1.基本概念 2.覆盖与交换 覆盖技术: 交换技术: 总结: 3.连续分配管理方式 单一连续分配 固定分区分配 动态分区分配 动态分区分配算法: 总结: 4.基本分页存储管理 定义&#xf…...

Spring缓存深入解析:@Cacheable的使用详解

摘要:在本文中,我们将深入研究Spring框架中的Cacheable注解。我们会通过详细的Java示例,探讨如何使用这个功能强大的注解来提升应用程序性能。 一、什么是缓存? 在计算机科学中,缓存是一种存储技术,用于保…...

软件配置安装(破解)--- jdk下载配置

下载jdk 如果有oracle账号的话直接登录下载你想要的版本 不然可以尝试镜像站 HUAWEI镜像:https://repo.huaweicloud.com/java/jdk/ 安装 配置(细节) 这里的JAVA_HOME就是java的家,也就是解压(或安装)之后的java的目录&#xff…...

idea使用docker生成镜像(打包镜像,导入镜像,导出镜像)

1:先下载安装dockerdesktop,安装成功后 2: 在cmd执行docker -v,查看安装的docker版本 C:\Users\dell>docker -v Docker version 24.0.5, build ced09963:需要启动 dockerdesktop应用,才算启动docker&a…...

wazuh环境配置

目录 一、wazuh的安装 1.1官方仓库安装 1.2虚拟机OVA安装 1.2.1 然后执行下面命令 1.2.2 这里还要下载脚本和config.yml配置文件,用来生成证书​编辑 1.2.3然后编辑config.yml文件,将下面的三个IP地址改为一样的 1.2.4运行./wazuh-certs-tool.sh以…...

【Linux】Linux下常用压缩解压缩指令及选项小结

0x00 前言 版本信息:Ubuntu 18.04.6 LTS 最后更新日期:2023.8.22 0x01 Linux下常用压缩解压缩指令小结 1.gzip指令 gzip file:压缩file文件为file.gz ,但是只能压缩文件不能压缩目录,且不保留源文件。若想打包目录…...

香蕉派社区推出带10G SFP+ 端口的Banana Pi BPI-R4 Wifi7开源路由器

香蕉派BPI-R4 根据著名Banana Pi品牌背后的公司Sinovoip提供的初步信息,他们即将推出的Banana Pi BPI-R4路由器板目前正在开发中。与之前的 Banana Pi R3 板相比,这在规格上将有显着提升。这就是我们目前所知道的。 您可以选择 R4 板的两种不同配置。具…...

A 题:震源属性识别模型构建与震级预测 :代码分析:

问题 1: 针对附件 1~8 中的地震波数据,找出一系列合适的指 标与判据,构建震源属性识别模型,进行天然地震事件(附件 1~7) 与非天然地震事件(附件 8)的准确区…...

源码分析CompletableFuture使用默认线程池ForkJoinPool的弊端

先说结论: 假如有20CompletableFuture任务并发执行时,都使用默认线程池ForkJoinPool,但cpu的核心数又小于3,那么就会新建20个线程(不使用默认线程池了),这20个线程相互竞争cpu资源和内存&#x…...

连接pgsql数据库 sslmode sslrootcert sslkey sslcert 参数的作用

sslmode 参数的作用 sslmode 参数用于指定数据库连接时使用的 SSL 加密模式。SSL(Secure Sockets Layer)是一种加密协议,用于保护数据在客户端和服务器之间的传输过程,以增加数据传输的安全性。sslmode 参数可以设置不同的值&…...

从零学算法3

3.给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例 2: 输入: “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串是 “b”&…...

宠物小程序开发

在当今社会,宠物已成为许多人生活中不可或缺的一部分。宠物市场的持续增长为创业者提供了巨大的商机。然而,作为一个创业者,要在竞争激烈的宠物市场中脱颖而出并不容易。因此,开发一个专属于自己的宠物小程序成为了解决这一难题的…...

07-Vue基础之综合案例——小黑记事本

个人名片: 😊作者简介:一名大二在校生 🤡 个人主页:坠入暮云间x 🐼座右铭:懒惰受到的惩罚不仅仅是自己的失败,还有别人的成功。 🎅**学习目标: 坚持每一次的学习打卡 文章…...

vite4+vue3+electron23.3+ts桌面应用bs端开发 打包windows、linux、max三个系统的安装包

vite4vue3electron23.3ts桌面应用bs端开发 打包windows、linux、max三个系统的安装包 主要包依赖 "electron-store": "^8.1.0", //全局数据状态管理,可选择性安装"electron": "23.3.8","electron-builder": &q…...

限制 el-input 输入 emoji

1. 电脑如何输入 emoji 表情 ? 快捷键 win; 或 win. 2. 代码实现 <template><el-input v-model"input" placeholder"请输入内容" input"inputChange"></el-input> </template><script> export default {name: D…...

【AI】解决Number_Words的安装和使用

It appears that you encountered an error while trying to install the “Numbers_Words” package using the specific version 0.18.2 of the PEAR channel. The error message indicates that there was a problem unpacking the “Math_BigInteger-1.0.3” package, whi…...

开启MySQL的binlog日志

在/etc/my.cnf增加如下配置 #binlog相关 log-bin /testdata/mysql/log/bin/mysql-bin expire_logs_days 7 binlog-format ROW binlog_cache_size 4M max_binlog_cache_size 20G binlog_rows_query_log_events 1 binlog_row_image FULL sync_binlog 1 log_bin_trust_fun…...

【支付宝小程序】支付宝小程序自定义组件技术教程

&#x1f996;我是Sam9029&#xff0c;一个前端 Sam9029的CSDN博客主页:Sam9029的博客_CSDN博客-JS学习,CSS学习,Vue-2领域博主 **&#x1f431;‍&#x1f409;&#x1f431;‍&#x1f409;恭喜你&#xff0c;若此文你认为写的不错&#xff0c;不要吝啬你的赞扬&#xff0c…...

CSDN编程题-每日一练(2023-08-23)

CSDN编程题-每日一练(2023-08-23) 一、题目名称:圆小艺二、题目名称:连续子数组的最大和三、题目名称:投篮一、题目名称:圆小艺 时间限制:1000ms内存限制:256M 题目描述: 最近小艺酱渐渐变成了一个圆滑的形状-球!! 小艺酱开始变得喜欢上球! 小艺酱得到n个同心圆。 …...

解决:Appium Inspector刷新页面一直加载转圈

目录 问题&#xff1a;Appium Inspector刷新页面一直加载转圈 解决办法&#xff1a; 1.进入设置页面-电池-后台耗电管理 2.找到下面3个应用&#xff0c;修改为允许后台高耗电 问题&#xff1a;Appium Inspector刷新页面一直加载转圈 1、手机进行操作后&#xff0c;Appium I…...

wordpress 不能自定义主题/自己如何建立网站

android8.1启动过程(七) SystemServer_we1less的博客-CSDN博客 这篇文章说道SystemServer进程主要用于创建系统服务&#xff0c;同时初始化Zygote 调用gCurRuntime->onZygoteInit();本文从这继续解析binder的启动过程。 onZygoteInit AOSP/frameworks/base/cmds/app_pr…...

北京高端网站建设系统/陕西网络营销优化公司

2-范数 欧几里得范数&#xff0c;常用计算向量长度&#xff09;&#xff0c;即向量元素绝对值的平方和再开方 参考资料 1.知乎&#xff1a;0 范数、1 范数、2 范数有什么区别&#xff1f; 2. Wikipedia&#xff1a;范数...

网站建设捌金手指花总十七/矿产网站建设价格

Github1、什么是 GitHub2、使用Github2.1创建Github账号2.2添加SSH Keys到Github账号2.2.1什么是SSH URL2.2.2 什么是SSH keys2.3将本地仓库与远端Github仓库关联起来2.3.1远端已建好的仓库本地克隆2.3.2把本地已有的同名Git与Github上的仓库关联1)先有本地库2)后有远程库的3)再…...

手机建站模版/seo软件服务

https://blog.csdn.net/u013948010/article/details/80520540 https://blog.csdn.net/chaipp0607/article/details/78885720...

黑科技软件网站/推广公司是做什么的

一. 静态库的生成 1. 测试目录: lib 2. 源码文件名: mywindow.h, mywindow.cpp, 类MyWindow继承于QPushButton, 并将文字设置为"Im in class MyWindow"; 3. 编写项目文件: mywindow.pro 注意两点: TEMPLATE lib CONFIG staticlib …...

海尔网站建设目标/长沙seo网站排名

Mosquitto库依赖libuuid和openssl库&#xff0c;所以我们在交叉编译Mosquitto之前需要先交叉编译他所需要的依赖库&#xff0c;这里作者已经把需要的源码都下载好了&#xff0c;大家可以在这个文档的目录下找到。不建议大家下载和我不一致的版本&#xff0c;可能会出问题。 mq…...