文章目录

  • 数据库约束
    • NOT NULL(非空约束)
    • UNIQUE(唯一约束)
    • DEFAULT(缺省约束)
    • PRIMARY KEY(主键约束)
    • AUTO_INCREMENT 自增
    • FOREIGN KEY(外键约束)
    • CHECK(检查约束)
  • 表的设计
    • 表的关系
      • 一对一
      • 一对多
      • 多对多
    • 三大范式
      • 第一范式
      • 第二范式
      • 第三范式

数据库约束

数据库中主要有六种约束:

  • NOT NULL(非空约束) - 指示某列不能存储 NULL 值。
  • UNIQUE(唯一约束) - 保证某列的每行必须有唯一的值。
  • DEFAULT(缺省约束) - 规定没有给列赋值时的默认值。
  • PRIMARY KEY(主键约束) - NOT NULLUNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录。
  • FOREIGN KEY(外键约束) - 保证一个表中的数据匹配另一个表中的值的参照完整性。
  • CHECK(检查约束) - 保证列中的值符合指定的条件。对于 MySQL 数据库,对 CHECK 子句进行分析,但是忽略 CHECK 子句。

NOT NULL(非空约束)

指示某列不能存储 NULL 值。

mysql> create table book(-> id int,-> name varchar(12),-> price double,-> publish date,-> num int NOT NULL-> );
Query OK, 0 rows affected (0.02 sec)// 可以看到 num 的 NULL 属性已经变为 NO(不允许)
mysql> DESC book;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id      | int         | YES  |     | NULL    |       |
| name    | varchar(12) | YES  |     | NULL    |       |
| price   | double      | YES  |     | NULL    |       |
| publish | date        | YES  |     | NULL    |       |
| num     | int         | NO   |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
5 rows in set (0.00 sec)// 尝试一下插入一个 num 为 NULL 的数据
mysql> INSERT INTO book VALUES(2, "C++", 13.6, "2000-08-02", NULL);
ERROR 1048 (23000): Column 'num' cannot be null// 可以发现会报错: num 列不可以为 NULL

UNIQUE(唯一约束)

保证某列的每行必须有唯一的值,即对于添加了唯一约束的数据项不能有重复。

mysql> create table book(-> id int UNIQUE,-> name varchar(12),-> price double,-> publish date,-> num int-> );
Query OK, 0 rows affected (0.03 sec)// 可以看到 id 的 key 属性已经被标记为 UNI
mysql> desc book;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id      | int         | YES  | UNI | NULL    |       |
| name    | varchar(12) | YES  |     | NULL    |       |
| price   | double      | YES  |     | NULL    |       |
| publish | date        | YES  |     | NULL    |       |
| num     | int         | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
5 rows in set (0.00 sec)mysql> INSERT INTO book VALUES(1, "C++", 13.5, NULL, 10);
Query OK, 1 row affected (0.00 sec)mysql> INSERT INTO book VALUES(1, "JAVA", 3.5, "2000-08-02", 5);
ERROR 1062 (23000): Duplicate entry '1' for key 'book.id'
// 虽然第二条数据除了 id,其他列的值都不同于第一条数据,然而还是会报错:重复输入“1”作为“book.id”的值

DEFAULT(缺省约束)

规定没有给列赋值时的默认值。

mysql> create table book(-> id int,-> name varchar(12),-> price double,-> publish date DEFAULT "2000-08-02",-> num int-> );
Query OK, 0 rows affected (0.02 sec)// 可以看到 publish 的 Default 属性被设置为 2000-08-02
mysql> desc book;
+---------+-------------+------+-----+------------+-------+
| Field   | Type        | Null | Key | Default    | Extra |
+---------+-------------+------+-----+------------+-------+
| id      | int         | YES  |     | NULL       |       |
| name    | varchar(12) | YES  |     | NULL       |       |
| price   | double      | YES  |     | NULL       |       |
| publish | date        | YES  |     | 2000-08-02 |       |
| num     | int         | YES  |     | NULL       |       |
+---------+-------------+------+-----+------------+-------+
5 rows in set (0.01 sec)// 指定列插入,不包含 publish 列
mysql> INSERT INTO book(id, name, price, num) VALUES(3, "C++", 13.5, 15);
Query OK, 1 row affected (0.00 sec)mysql> SELECT * FROM book;
+------+------+-------+------------+------+
| id   | name | price | publish    | num  |
+------+------+-------+------------+------+
|    3 | C++  |  13.5 | 2000-08-02 |   15 |
+------+------+-------+------------+------+
1 rows in set (0.00 sec)

PRIMARY KEY(主键约束)

NOT NULLUNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录。

主键(primary key)的特性即 非空且唯一,如果在没有指定主键的时候,如果某一列(或一组列)具有非空且唯一的特性,他就会被暂定为主键,但是主键只能有一个。

表中的任何列都可以作为主键,只要它满足以下条件:

  • 任意两行都不具有相同的主键值;
  • 每个行都必须具有一个主键值(主键列不允许NULL值)。

上面提到多个列也可以作为主键。在使用多列作为主键时,上述条件必须应用到构成主键的所有列,所有列值的 组合 必须是唯一的(但单个列的值可以不唯一)。

除MySQL强制实施的规则外,应该坚持的几个普遍认可的最好习惯为:

  • 不更新主键列中的值;
  • 不重用主键列的值;
  • 不在主键列中使用可能会更改的值。(例如,如果使用一个名字作为主键以标识某个供应商,当该供应商合并和更改其名字时,必须更改这个主键。)
// 使用  NOT NULL UNIQUE
mysql> CREATE TABLE pen(-> id int NOT NULL UNIQUE,-> name varchar(12),-> price double,-> num int-> );
Query OK, 0 rows affected (0.06 sec)// id 的 KEY 属性变为 PRI
mysql> DESC pen;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int         | NO   | PRI | NULL    |       |
| name  | varchar(12) | YES  |     | NULL    |       |
| price | double      | YES  |     | NULL    |       |
| num   | int         | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)// 使用 PRIMARY KEY
mysql> CREATE TABLE clothes(-> id int PRIMARY KEY,-> name varchar(12),-> price double,-> num int-> );
Query OK, 0 rows affected (0.02 sec)// id 的 KEY 属性变为 PRI
mysql> DESC clothes;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int         | NO   | PRI | NULL    |       |
| name  | varchar(12) | YES  |     | NULL    |       |
| price | double      | YES  |     | NULL    |       |
| num   | int         | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
4 rows in set (0.01 sec)

但是 非空且唯一 并不一定就是主键,如果有多个非空不唯一,则只有第一个是主键。

// 将 id 和 num 都设置为非空且唯一
mysql> CREATE TABLE pen(-> id int NOT NULL UNIQUE,-> name varchar(12),-> price double,-> num int UNIQUE NOT NULL-> );
Query OK, 0 rows affected (0.02 sec)// 只有 id 是 PRI
mysql> DESC pen;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int         | NO   | PRI | NULL    |       |
| name  | varchar(12) | YES  |     | NULL    |       |
| price | double      | YES  |     | NULL    |       |
| num   | int         | NO   | UNI | NULL    |       |
+-------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

但我们之前也提到过,是允许 多个列 组成主键的,那么怎么实现呢?

mysql> CREATE TABLE pen(-> id int PRIMARY KEY,-> name varchar(12) PRIMARY KEY,-> price double,-> num int-> );
ERROR 1068 (42000): Multiple primary key defined

通过报错我们发现,如果在两个列后分别声明主键的话会被认为 定义了多个主键。

// 正确做法是在声明完所有列之后,再声明主键是由哪些列构成的
mysql> CREATE TABLE pen(-> id int,-> name varchar(12),-> price double,-> num int,-> PRIMARY KEY(id, name)-> );
Query OK, 0 rows affected (0.03 sec)mysql> DESC pen;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int         | NO   | PRI | NULL    |       |
| name  | varchar(12) | NO   | PRI | NULL    |       |
| price | double      | YES  |     | NULL    |       |
| num   | int         | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
4 rows in set (0.01 sec)

AUTO_INCREMENT 自增

添加自增属性的项必须为数字,并且必须为主键,并且只有缺省的时候才会使用自增。

  • 如果插入的 AUTO_INCREMENT 属性的列值为缺省,则赋值为上一条记录的值 +1 ,没有上一条记录,则赋值为 1
  • 如果删除了表中数据,序号并不会重置,而是继续从删除的位置自增。
mysql> CREATE TABLE pen(-> id int PRIMARY KEY AUTO_INCREMENT,-> name varchar(12),-> price double,-> num int-> );
Query OK, 0 rows affected (0.02 sec)// 可以看到 id 的 Extra 属性变成了 auto_increment
mysql> DESC pen;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int         | NO   | PRI | NULL    | auto_increment |
| name  | varchar(12) | YES  |     | NULL    |                |
| price | double      | YES  |     | NULL    |                |
| num   | int         | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)// 加入一条未设 id 的数据
mysql> INSERT INTO pen(name, price, num) VALUES("A", 2.34, 5);
Query OK, 1 row affected (0.01 sec)// id 被自动设置为 1
mysql> SELECT * FROM pen;
+----+------+-------+------+
| id | name | price | num  |
+----+------+-------+------+
|  1 | A    |  2.34 |    5 |
+----+------+-------+------+
1 row in set (0.00 sec)// 增加两条数据,一条设置 id
mysql> INSERT INTO pen VALUES(3, "B", 3.45, 7);
Query OK, 1 row affected (0.00 sec)
// 一条不设 id
mysql> INSERT INTO pen(name, price, num) VALUES("C", 6.34, 10);
Query OK, 1 row affected (0.00 sec)// 未设 id 的数据其 id 会变成上一条记录的 id+1
mysql> SELECT * FROM pen;
+----+------+-------+------+
| id | name | price | num  |
+----+------+-------+------+
|  1 | A    |  2.34 |    5 |
|  3 | B    |  3.45 |    7 |
|  4 | C    |  6.34 |   10 |
+----+------+-------+------+
3 rows in set (0.00 sec)// 删掉所有 id<=4 的数据
mysql> DELETE FROM pen WHERE id <= 4;
Query OK, 3 rows affected (0.00 sec)// 增加两条数据,都没有设置 id 值
mysql> INSERT INTO pen(name, price, num) VALUES("D", 7.34, 1);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO pen(name, price, num) VALUES("E", 12.34, 13);
Query OK, 1 row affected (0.00 sec)// 新增的两条数据的 id 并不是从 1 开始,而是根据上一条记录(虽然它已经不存在了)的 id 自增
mysql> SELECT * FROM pen;
+----+------+-------+------+
| id | name | price | num  |
+----+------+-------+------+
|  5 | D    |  7.34 |    1 |
|  6 | E    | 12.34 |   13 |
+----+------+-------+------+
2 rows in set (0.00 sec)

FOREIGN KEY(外键约束)

外键:外键为表中的某一列,包含了另一个表的主键,定义了两个表之间的关系。例如学生表中存储了班级的信息,但是在班级表中并没有这个班级存在,就会导致数据出现冲突,所以必须将两个表关联起来。

语法

FOREIGN KEY (外键项) REFERENCES 关联表名(关联表中的对应项)

示例

// 创建班级表
mysql> CREATE TABLE class(-> id int PRIMARY KEY AUTO_INCREMENT-> );
Query OK, 0 rows affected (0.03 sec)
// 创建学生表
mysql> CREATE TABLE student(-> id int PRIMARY KEY AUTO_INCREMENT,-> num int,-> name varchar(10),-> classid int,-> FOREIGN KEY (classid) REFERENCES class(id)-> );
Query OK, 0 rows affected (0.03 sec)
// 创建两个班级
mysql> INSERT INTO class VALUES(181);
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO class VALUES(182);
Query OK, 1 row affected (0.00 sec)
// 插入三条学生数据
mysql> INSERT INTO student(name, classid) VALUES("李四", 182);
Query OK, 1 row affected (0.03 sec)
mysql> INSERT INTO student(name, classid) VALUES("陈六", 181);
Query OK, 1 row affected (0.00 sec)
// 第三条失败,原因在于没有186班
mysql> INSERT INTO student(name, classid) VALUES("张三", 186);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`classid`) REFERENCES `class` (`id`))

CHECK(检查约束)

保证列中的值符合指定的条件。对于MySQL数据库,对CHECK子句进行分析,但是忽略CHECK子句。

mysql> CREATE TABLE stu(-> id int,-> age int,-> name varchar(10),-> CHECK(id < 5)-> );
Query OK, 0 rows affected (0.03 sec)mysql> INSERT INTO stu(id) VALUES(3);
Query OK, 1 row affected (0.01 sec)mysql> INSERT INTO stu(id) VALUES(8);
ERROR 3819 (HY000): Check constraint 'stu_chk_1' is violated.
mysql> SELECT * FROM stu;
+------+------+------+
| id   | age  | name |
+------+------+------+
|    3 | NULL | NULL |
+------+------+------+
1 row in set (0.00 sec)

值得一提的是,在 MySQL 8.0.16 版本之前的 CHECK 约束,能被解析但是被忽略掉了,就是 不符合CHECK的数据依然可以被加入到表中。 而在之后的版本上,支持 CHECK约束,但仍有缺陷!想要 INSER INTO 一个不满足 CHECK 的数据时确实不能通过(详见上面的示例中),但是如果 INSERT INTO 时,未设置被 CHECK 约束的 ,那么 即使这个列的默认值不符合 CHECK约束 ,也还是可以创建成功。

可以看到 主动赋值 不满足 CHECK 的语句会报错,而 默认值 不满足 CHECK 的语句却可以成功插入。


表的设计

表的关系

一对一

例如人和身份证的关系,每个人都对应有着只属于自己的身份证:


一对多

例如学生和班级的关系,一个班级拥有多个学生,但是一个学生只能属于一个班级:


多对多

例如学生、课程、选课表的关系。一个学生可以选择多门课程,一个课程也可以被多个学生选择:


三大范式

表的关系只是设计的最基础的一项,考虑好关系,确认好数据项,将数据填进去即可。
但是那样的设计并不合理,可能会存在 数据冗余、传输性能、查询性能 等问题,所以需要用到三大范式来规范数据库表的设计,减少数据库的冗余性。

范式是针对数据库表设计的几种方案,目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。

通常我们使用的都是第一范式(1NF)、第二范式(2NF)、第三范式(3NF),所以又将他们称为三大范式。

第一范式

要求数据库表的每一列都是不可分割的原子数据项。


在这个表中,家庭信息和学校信息并不是原子的,例如家庭信息中包含了家庭组成和所在地,学校信息包含了年级和学位。

对于第一范式,需要确保每一项数据都是不可分割的原子性数据,不能是一个集合。因此要做出如下调整:


第二范式

在第一范式的基础上,非主键数据必须完全依赖主键,不能部分依赖(针对组合主键)。

拿下面这个表来说,相同 订单号订单时间和订单金额一样 的,但是相同 产品号订单时间和订单金额不一样 。这说明订单时间和订单金额 部分依赖主键 —— 只依赖了组合主键中的订单号而没有依赖产品号 。

所以需要将其分割出去单独建立一个表:


第三范式

在第二范式的基础上,每一个非主键数据都必须要和主键直接依赖而非间接依赖,即不能依赖非主键数据。旨在体现依赖关系不可传递性。

如下图,班主任性别班主任年龄 直接依赖于班主任姓名(非主键数据),而与 主键——学号 并没有直接的依赖关系,而是间接,这就是依赖传递:

所以需要将这两项分割出去单独建表:

MySQL | 数据库的六种约束、表的关系、三大范式相关推荐

  1. MySQL数据库中的多表查询含义以及练习~建议码友们点亮拇指+收藏呐~

    MySQL数据库中的多表查询含义以及练习 一. 多表查询含义 二. 多表查询练习 1. 已知表 2. 需求And代码 一. 多表查询含义 查询语法: select列名列表from表名列表where条件 ...

  2. day 1 学习MySQL数据库作业 - 创建员工表思考与表之间的关系

    day 1 学习MySQL数据库作业 创建员工表 (工号.姓名.性别.出生日期.入职日期.月薪.职位) 思考员工表跟部门表之间有没有关系?如果有是什么关系?如何建立两张表的关系? 1.创建员工表 (工 ...

  3. MySQL学习笔记05【多表操作、三大范式、数据库的备份和还原】

    MySQL 文档-黑马程序员(腾讯微云):https://share.weiyun.com/RaCdIwas 1-MySQL基础.pdf.2-MySQL约束与设计.pdf.3-MySQL多表查询与事务 ...

  4. Hibernate连接mysql数据库并自动创建表

    天才第一步,雀氏纸尿裤,Hibernate第一步,连接数据库. Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个 ...

  5. mysql数据库约束详解_基于MySQL数据库的数据约束实例及五种完整性约束介绍

    为了防止不符合规范的数据进入数据库,在用户对数据进行插入.修改.删除等操作时,DBMS自动按照一定的约束条件对数据进行监测,使不符合规范的数据不能进入数据库,以确保数据库中存储的数据正确.有效.相容. ...

  6. 七、Mysql数据库的数据类型和表属性

    Mysql数据库的数据类型和表属性 七.Mysql数据库的数据类型和表属性 一.SQL介绍 二.常用SQL分类 三.数据类型.表属性.字符集 1.数据类型 2.种类 数值类型 字符类型 时间类型 二进 ...

  7. java查询mysql装载bean_jsp与javabean链接mysql数据库并查询数据表的简单实例源码

    jsp与javabean链接mysql数据库并查询数据表的简单实例源码.这个简单的实例是给新手学习的,或者一些高手临时忘记怎么使用jsp操作mysql数据库时候查找的,包括了建立mysql数据库连接的 ...

  8. shell判端mysql数据库是否存在_Shell脚本检测和检查mysql数据库是否存在坏表

    shell脚本检测和检查mysql数据库是否存在坏表 此脚本的主要用途是检测mysql服务器上所有的数据库或者单独数据库中的坏表,适用于RHEL/Centos系列 #!/bin/bash #此脚本的主 ...

  9. MySQL数据库的分库分表方案

    MySQL数据库的分库分表方案 一. 数据库瓶颈 不管是IO瓶颈,还是CPU瓶颈,最终都会导致数据库的活跃连接数增加,进而逼近甚至达到数据库可承载活跃连接数的阈值.在业务Service来看就是,可用数 ...

最新文章

  1. java垃圾回收机制_乐字节Java|GC垃圾回收机制、package和import语句
  2. CV之IC: 图像描述(Image Captioning) 的简介、使用方法、案例应用之详细攻略
  3. 游戏必备组件有哪些_面试必备:2019Vue经典面试题总结(含答案)
  4. dz论坛php.ini设置,Discuz!X1.5至3.2论坛Win主机与Linux主机伪静态设置方法
  5. 由partition看窗口函数
  6. win7临时文件_教你win7网页打开慢的应对办法
  7. conda报错Collecting package metadata
  8. mysql 事件调度器_【MySQL】事件调度器 (Event Scheduler)
  9. MySql的架构和历史
  10. Three.js – Building a Cube with different mater...
  11. 如何避免后台IO高负载造成的长时间JVM GC停顿(转)
  12. VS实用小工具(检测代码内存泄漏等问题)
  13. Enterprise Architect(EA)画UML之用例图,敲详细讲解+实战举例
  14. SpringBoot官方文档学习
  15. Linux ruby离线安装
  16. 网页设计配色应用——色彩的调和
  17. 【2022国赛模拟】摆(bigben)——行列式、杜教筛
  18. 【微信小程序】2、SpringBoot整合WxJava接入微信客服
  19. 新西兰做java_新西兰华人的真实生活,真是吓到我了
  20. 百度统计 渠道分析 渠道名称显示 未知

热门文章

  1. des 向量 java_在JAVA中使用DES算法
  2. SOCKET bind INADDR_LOOPBACK和INADDR_ANY的区别
  3. linux内核I2C子系统学习(一)
  4. 取消一个请求(Cancel)
  5. nubia android root权限,获取中兴NX403a (Nubia Z5S Mini Android 4.2)ROOT权限教程,新手必看...
  6. 【转】DICOM医学图像处理:DIMSE消息发送与接收“大同小异”之DCMTK fo-dicom mDCM
  7. 【转】Postman系列三:Postman中post接口实战(上传文件、json请求)
  8. nuget 包版本冲突解决 packages.config
  9. 写第一个spark程序(wordcount)
  10. Python 数据分析三剑客之 NumPy(六):矩阵 / 线性代数库与 IO 操作