【MySQL】表的约束

目录

一、空属性

二、默认值

三、列描述

四、zerofill

五、主键

六、自增长

七、唯一键

八、外键


在MySQL数据库中,虽然数据类型定义了字段可以存储的数据种类,但为了进一步确保数据的准确性和业务逻辑的正确性,我们需要额外的约束条件来保证数据的合法性,从业务逻辑角度保证数据的正确性。

一、空属性

NULL (默认的)/ NOT NULL(不为空)

  • NULL 允许字段值为空,即该字段可以没有数据。
  • NOT NULL 要求字段必须有值,不允许为空。

说明:

  • NULL 表示没有,不是为0,不参与运算,例如 2+null 还是null (null和NULL相同,只是大小写不同)。
  • 数据库默认字段基本都是字段为空,实际开发时,尽可能保证字段不为空,因为数据为空没办
    法参与运算。

示例:

创建一个班级表,包含班级名和班级所在的教室。

在正常的业务逻辑中:

  • 如果班级没有名字,你不知道你在哪个班级
  • 如果教室名字可以为空,就不知道在哪上课

所以我们在设计数据库表的时候,一定要在表中进行限制,满足上面条件的数据就不能插入到表中。这就是"约束"。

sql 复制代码
mysql> create table myclass(
    -> class_name varchar(20) not null,
    -> class_room varchar(10) not null);
Query OK, 0 rows affected (0.03 sec)

mysql> desc myclass;
+------------+-------------+------+-----+---------+-------+
| Field      | Type        | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| class_name | varchar(20) | NO   |     | NULL    |       |
| class_room | varchar(10) | NO   |     | NULL    |       |
+------------+-------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

mysql> insert into myclass(class_name) values('class1');
ERROR 1364 (HY000): Field 'class_room' doesn't have a default value

二、默认值

DEFAULT 或 default

默认值:某一种数据会经常性的出现某个具体的值,可以在一开始就指定好,在需要真实数据的时候,用户可以选择性的使用默认值。

  • 为字段指定一个默认值,当插入记录时,如果未明确给出该字段的值,则自动使用默认值。
  • 只有设置了default的列,才可以在插入值的时候,对列进行省略。
  • 空属性和默认值不冲突,相互补充。
  • 可以既指定not null 又指定default,一般不需要同时出现。
  • 如果建表时没有指定默认值,那就为default null。
  • 设置not null就不会自动设置default。
  • not null 指定的列,如果添加元素时忽略该列,就根据其是否设置default判断能否成功插入。
sql 复制代码
mysql> create table tt10 (
    -> name varchar(20) not null,
    -> age tinyint unsigned default 0,
    -> sex char(2) default '男');
Query OK, 0 rows affected (0.03 sec)

mysql> desc tt10;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| name  | varchar(20)      | NO   |     | NULL    |       |
| age   | tinyint unsigned | YES  |     | 0       |       |
| sex   | char(2)          | YES  |     | 男      |       |
+-------+------------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

mysql> insert into tt10(name) values('zhangsan');
Query OK, 1 row affected (0.00 sec)

mysql>  select * from tt10;
+----------+------+------+
| name     | age  | sex  |
+----------+------+------+
| zhangsan |    0 | 男   |
+----------+------+------+
1 row in set (0.00 sec)

三、列描述

COMMENT

列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或DBA来进行了解。

  • 提供字段或表的描述信息,虽然它不影响数据存储或查询,但有助于其他开发者或未来的你理解字段或表的作用。
  • 通过 desc 查看不到注释信息,通过show可以看到。
sql 复制代码
mysql> create table tt12 (
    -> name varchar(20) not null comment '姓名',
    -> age tinyint unsigned default 0 comment '年龄',
    -> sex char(2) default '男' comment '性别');
Query OK, 0 rows affected (0.03 sec)

mysql> desc tt12;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| name  | varchar(20)      | NO   |     | NULL    |       |
| age   | tinyint unsigned | YES  |     | 0       |       |
| sex   | char(2)          | YES  |     | 男      |       |
+-------+------------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

mysql> show create table tt12\G
*************************** 1. row ***************************
       Table: tt12
Create Table: CREATE TABLE `tt12` (
  `name` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '姓名',
  `age` tinyint unsigned DEFAULT '0' COMMENT '年龄',
  `sex` char(2) COLLATE utf8mb4_unicode_ci DEFAULT '男' COMMENT '性别'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.00 sec)

四、zerofill

sql 复制代码
mysql> create table tt3 ( a int unsigned, b int);
Query OK, 0 rows affected (0.03 sec)

mysql> show create table tt3\G
*************************** 1. row ***************************
       Table: tt3
Create Table: CREATE TABLE `tt3` (
  `a` int unsigned DEFAULT NULL,
  `b` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.00 sec)

mysql> insert into tt3 values(1,2);
Query OK, 1 row affected (0.00 sec)

mysql> select * from tt3;
+------+------+
| a    | b    |
+------+------+
|    1 |    2 |
+------+------+
1 row in set (0.00 sec)

对a列添加了zerofill属性,再进行查找,返回如下结果:

sql 复制代码
mysql> alter table tt3 change a a int(5) unsigned zerofill;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 2

mysql> show create table tt3\G
*************************** 1. row ***************************
       Table: tt3
Create Table: CREATE TABLE `tt3` (
  `a` int(5) unsigned zerofill DEFAULT NULL,
  `b` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.00 sec)

mysql> select * from tt3;
+-------+------+
| a     | b    |
+-------+------+
| 00001 |    2 |
+-------+------+
1 row in set (0.00 sec)

这次可以看到a的值由原来的1变成00001,这就是zerofill属性的作用,如果宽度小于设定的宽度(这里设置的是5),自动填充0。要注意的是,这只是最后显示的结果,在MySQL中实际存储的还是1。

五、主键

主键:primary key用来唯一的约束该字段里面的数据,不能重复,不能为空。

  • 一张表中最多只能有一个主键。
  • 主键所在的列通常是整数类型。
  • 建议将主键设计成与当前业务无关的字段,当业务调整时,尽量不会对主键做过大的调整。

用法:

  • 当表创建好以后但是没有主键的时候,可以使用DDL语句再次追加主键。
sql 复制代码
alter table 表名 add primary key(字段列表)
  • 删除主键
sql 复制代码
alter table 表名 drop primary;
  • 复合主键
    在创建表的时候,在所有字段之后,使用primary key(主键字段列表)来创建主键,如果有多个字段作为主键,可以使用复合主键。
sql 复制代码
mysql> create table tt14( 
    -> id int unsigned, 
    -> course char(10) comment '课程代码', 
    -> score tinyint unsigned default 60 comment '成绩', 
    -> primary key(id, course) );
Query OK, 0 rows affected (0.03 sec)

mysql> desc tt14;
+--------+------------------+------+-----+---------+-------+
| Field  | Type             | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+-------+
| id     | int unsigned     | NO   | PRI | NULL    |       |
| course | char(10)         | NO   | PRI | NULL    |       |
| score  | tinyint unsigned | YES  |     | 60      |       |
+--------+------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> insert into tt14 (id,course)values(1, '123');
Query OK, 1 row affected (0.01 sec)

mysql> insert into tt14 (id,course)values(1, '123');
ERROR 1062 (23000): Duplicate entry '1-123' for key 'tt14.PRIMARY'

示例:

创建表的时候直接在字段上指定主键

sql 复制代码
mysql> create table tt13 (
    -> id int unsigned primary key comment '学号不能为空',
    -> name varchar(20) not null);
Query OK, 0 rows affected (0.03 sec)

mysql> desc tt13;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id    | int unsigned | NO   | PRI | NULL    |       |
| name  | varchar(20)  | NO   |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

主键对应的字段中不能重复,一旦重复,操作失败。

sql 复制代码
mysql> insert into tt13 values(1, 'aaa');
Query OK, 1 row affected (0.01 sec)

mysql> insert into tt13 values(1, 'bbb');
ERROR 1062 (23000): Duplicate entry '1' for key 'tt13.PRIMARY'

删除主键

sql 复制代码
 alter table tt13 drop primary key;

mysql>  alter table tt13 drop primary key;
Query OK, 1 row affected (0.09 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> desc tt13;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id    | int unsigned | NO   |     | NULL    |       |
| name  | varchar(20)  | NO   |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

六、自增长

auto_increment:自增长。

  • 当对应的字段插入新记录且未指定字段值时,自动为该字段生成一个递增的数值,系统会从当前字段中已经有的最大值+1操作,得到一个新的不同的值。
  • 通常和主键搭配使用,作为逻辑主键。
  • 原理:表外设置了auto_increment的值,代表下次增长的起始值(可以在建表时指定起始值)。

自增长的特点:

  • 任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)
  • 自增长字段必须是整数
  • 一张表最多只能有一个自增长

查看最后一个自增长的值

sql 复制代码
select last_insert_id();

示例:

sql 复制代码
mysql> create table tt15(
    -> id int unsigned primary key auto_increment,
    -> name varchar(10) not null default '');
Query OK, 0 rows affected (0.04 sec)

mysql> desc tt15;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | int unsigned | NO   | PRI | NULL    | auto_increment |
| name  | varchar(10)  | NO   |     |         |                |
+-------+--------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> insert into tt15(name) values('a');
Query OK, 1 row affected (0.01 sec)

mysql> select last_insert_id(tt15);
ERROR 1054 (42S22): Unknown column 'tt15' in 'field list'
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
|                1 |
+------------------+
1 row in set (0.00 sec)

mysql> insert into tt15(name) values('b');
Query OK, 1 row affected (0.00 sec)

mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
|                2 |
+------------------+
1 row in set (0.00 sec)

mysql> show create table tt15\G
*************************** 1. row ***************************
       Table: tt15
Create Table: CREATE TABLE `tt15` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.00 sec)

AUTO_INCREMENT=3,表示下次自增长的起始值为3。

索引:

在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。

索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。

索引提供指向存储在表的指定列中的数据值的指针,然后根据您指定的排序顺序对这些指针排序。数据库使用索引以找到特定值,然后顺指针找到包含该值的行。这样可以使对应于表的SQL语句执行得更快,可快速访问数据库表中的特定信息。

七、唯一键

unique:唯一键

唯一键是用于保证数据唯一性的一个约束,它确保表中的一列或列组合中的数据是唯一的,即表中不会有两行具有相同的列值。

唯一键的特点:

  • 唯一键确保字段或字段组合中的数据是唯一的,即表中不会有两条记录在这些字段上具有相同的值。
  • 与主键不同,唯一键允许字段值为NULL。
  • 一个表可以有多个唯一键约束,每个唯一键可以应用于不同的字段或字段组合。
  • 可以在创建表时定义唯一键,也可以在表创建之后通过ALTER TABLE语句添加。
  • 唯一键和主键不冲突,可以相互补充。主键更多的是标识唯一性的,二唯一键更多的是保证在业务上不要和别的信息出现重复。(类似于学生信息中的学号和电话号码)

示例:

sql 复制代码
mysql> create table student(
    -> id char(10) primary key comment '学号',
    -> name varchar(20) not null,
    -> phone_number varchar(20) unique);
Query OK, 0 rows affected (0.04 sec)

mysql> desc student;
+--------------+-------------+------+-----+---------+-------+
| Field        | Type        | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| id           | char(10)    | NO   | PRI | NULL    |       |
| name         | varchar(20) | NO   |     | NULL    |       |
| phone_number | varchar(20) | YES  | UNI | NULL    |       |
+--------------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> insert into student (id,name,phone_number) values('10001','张三','123345');
Query OK, 1 row affected (0.00 sec)

mysql> insert into student (id,name,phone_number) values('10002','张三','123345');
ERROR 1062 (23000): Duplicate entry '123345' for key 'student.phone_number'
mysql> insert into student (id,name) values('10003','李四');
Query OK, 1 row affected (0.01 sec)

mysql> insert into student (id,name,phone_number) values('10004','王五', null);
Query OK, 1 row affected (0.01 sec)

mysql> select * from student;
+-------+--------+--------------+
| id    | name   | phone_number |
+-------+--------+--------------+
| 10001 | 张三   | 123345       |
| 10003 | 李四   | NULL         |
| 10004 | 王五   | NULL         |
+-------+--------+--------------+
3 rows in set (0.00 sec)

八、外键

foreign key:外键

外键强调表与表之间的关联和约束,以保证数据完整性。(主表和从表)

**用法:**创建从表时单加一列。

sql 复制代码
foreign key (从表的列名/字段名) references 主表名(主表列名)

示例:

创建两个表:

  • 学生表stu(id, name, class_id) 学号、姓名和班级编号
  • 班级表myclass(id, name) 班级编号和班级名

使用一张表的原因:如果将班级表中的数据都设计在每个学生表的后面,那就会出现数据冗余,所以我们只要设计成让stu->class_id和myclass->id形成关联的关系 =>外键约束

步骤:

  1. 先创建主表
sql 复制代码
mysql> create table myclass(  
    -> id int primary key,
    -> name varchar(30) not null
    -> );
  1. 再创建从表
sql 复制代码
mysql> create table stu (
    -> id int primary key,
    -> name varchar(30) not null,
    -> class_id int,
    -> foreign key(class_id) reference myclass(id)
    -> );
  1. 正常插入数据
sql 复制代码
mysql> insert into myclass values(101, '计算机1班'),(102, '计算机2班');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> insert into stu values(12301, '张三', 101),(12302, '李四',102);
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0
  1. 插入错误的数据会不成功,例如插入一个不存在的班级
sql 复制代码
mysql> insert into stu values(12303, '王五', 103);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`mytest`.`stu`, CONSTRAINT `stu_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `myclass` (`id`))
  1. 插入学生的班级编号为空,即新来的同学还没有分配班级
sql 复制代码
mysql> insert into stu values(12303, '王五', null);
Query OK, 1 row affected (0.00 sec)

mysql> select * from stu;
+-------+--------+----------+
| id    | name   | class_id |
+-------+--------+----------+
| 12301 | 张三   |      101 |
| 12302 | 李四   |      102 |
| 12303 | 王五   |     NULL |
+-------+--------+----------+
3 rows in set (0.00 sec)

注意事项:

  1. 主表删除记录时,要保证从表中外键字段对应的记录个数为0,如果从表中存在任何匹配的外键记录,则拒绝删除主表中的记录。
  2. 从表增加记录时,会检查外键值是否在主表中存在。

在创建外键约束时,可以使用ON DELETE子句来指定当主表中的记录被删除时,从表应该采取的行为。以下是几种可能的ON DELETE行为:

  • RESTRICT:如果从表中存在任何匹配的外键记录,则拒绝删除主表中的记录。(默认行为)
  • CASCADE:当删除主表中的记录时,自动删除所有从表中匹配的外键记录。
  • SET NULL:当删除主表中的记录时,将从表中所有匹配的外键记录的字段设置为NULL(前提是从表的外键字段允许NULL值)。
相关推荐
陈卓4101 分钟前
MySQL-主从复制&分库分表
android·mysql·adb
IT项目管理34 分钟前
达梦数据库DMHS介绍及安装部署
linux·数据库
你都会上树?42 分钟前
MySQL MVCC 详解
数据库·mysql
大春儿的试验田1 小时前
高并发收藏功能设计:Redis异步同步与定时补偿机制详解
java·数据库·redis·学习·缓存
Ein hübscher Kerl.1 小时前
虚拟机上安装 MariaDB 及依赖包
数据库·mariadb
长征coder2 小时前
AWS MySQL 读写分离配置指南
mysql·云计算·aws
醇醛酸醚酮酯2 小时前
Qt项目锻炼——TODO清单(二)
开发语言·数据库·qt
ladymorgana2 小时前
【docker】修改 MySQL 密码后 Navicat 仍能用原密码连接
mysql·adb·docker
PanZonghui2 小时前
Centos项目部署之安装数据库MySQL8
linux·后端·mysql
GreatSQL社区2 小时前
用systemd管理GreatSQL服务详解
数据库·mysql·greatsql