前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >多表间的关系-一对多-多对多-一对一-外键约束

多表间的关系-一对多-多对多-一对一-外键约束

作者头像
Devops海洋的渔夫
发布2022-01-17 14:28:22
5.8K0
发布2022-01-17 14:28:22
举报
文章被收录于专栏:Devops专栏

11. 多表间的关系-一对多-多对多-一对一-外键约束

1. 表关系概述

现实生活中,实体与实体之间肯定是有关系的,比如:老公和老婆,部门和员工,用户和订单、订单和商品、学生和课程等等。那么我们在设计表的时候,就应该体现出表与表之间的这种关系!表和表之间的关系分成三种:

  1. 一对一 (老公和老婆)
  2. 一对多 (部门和员工, 用户和订单)
  3. 多对多 (学生和课程)

例如:

双11当天,马哥和东哥两个用户分别在淘宝上下了一些订单,已知马哥下了1个订单,订单总金额为999元. 东哥下了2个订单,订单金额分别为1314元和10元.

思考: 数据库该如何存放这些数据呢?

没有建立关系前: 通过表数据不能得知数据间的联系,这样存放数据是没有意义的

image-20200529100830282

建立关系后:

通过对该业务的分析,可得知一个用户可以有多个订单,一个订单只属于一个用户.

我们管1的一方,叫主表或1表. 我们管多个一方,叫从表或多表.

通常要在多的一方添加一个字段,用于存放主表主键的值,我们管这个字段叫外键字段.

外键字段的值必须为主表主键的值,若为其他值,则没有意义.

image-20200529101003797

用于限制外键字段取值必须为主表主键的值的约束叫做-外键约束.

2. 一对多

一对多(1:n) 例如:班级和学生,部门和员工,客户和订单,分类和商品 一对多建表原则: 在从表(多方)创建一个字段,指向主表(一方)的主键.我们把这个字段称之为外键.

3. 多对多

多对多(m:n) 例如:老师和学生,学生和课程,用户和角色 多对多关系建表原则: 需要创建第三张表,中间表中至少两个字段,这两个字段分别作为外键指向各自一方的主键。

4. 一对一

一对一(1:1) 在实际的开发中应用不多.因为一对一可以创建成一张表。两种建表原则:

  • 外键唯一:主表的主键和从表的外键(唯一),形成主外键关系,外键唯一UNIQUE
  • 外键是主键:主表的主键和从表的主键,形成主外键关系

5. 外键约束

5.1 什么是外键约束

一张表中的某个字段引用另一个表的主键 主表:约束别人 副表/从表:使用别人的数据,被别人约束

5.2 创建外键

  1. 新建表时增加外键:[CONSTRAINT] [外键约束名称] FOREIGN KEY(外键字段名) REFERENCES 主表名(主键字段名) 关键字解释:CONSTRAINT -- 约束关键字 FOREIGN KEY(外键字段名) –- 某个字段作为外键 REFERENCES -- 主表名(主键字段名) 表示参照主表中的某个字段
  2. 已有表增加外键:ALTER TABLE 从表 ADD [CONSTRAINT] [外键约束名称] FOREIGN KEY (外键字段名) REFERENCES 主表(主键字段名);

具体操作:

以"新建表时添加外键"演示
代码语言:javascript
复制
-- 先创建部门表
CREATE TABLE department (
 id INT PRIMARY KEY AUTO_INCREMENT,
 dep_name VARCHAR(20),
 dep_location VARCHAR(20)
);

-- 添加2个部门
INSERT INTO department (dep_name, dep_location) VALUES ('研发部', '广州'), ('销售部', '深圳');

-- 然后创建员工表,添加外键约束
CREATE TABLE employee (
 id INT PRIMARY KEY AUTO_INCREMENT,
 NAME VARCHAR(20),
 age INT,
 dep_id INT,
 -- 添加一个外键
 -- 外键取名公司要求,一般fk结尾
 CONSTRAINT emp_depid_ref_dep_id_fk FOREIGN KEY(dep_id) REFERENCES department(id)
);

执行如下:

代码语言:javascript
复制
-- 先创建部门表
mysql> CREATE TABLE department (
    -> id INT PRIMARY KEY AUTO_INCREMENT,
    -> dep_name VARCHAR(20),
    -> dep_location VARCHAR(20)
    -> );
Query OK, 0 rows affected (0.02 sec)

-- 添加2个部门
mysql> INSERT INTO department (dep_name, dep_location) VALUES ('研发部', '广州'), ('销售部', '深圳');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

-- 查看部门的数据
mysql> select * from department;
+----+-----------+--------------+
| id | dep_name  | dep_location |
+----+-----------+--------------+
|  1 | 研发部    | 广州         |
|  2 | 销售部    | 深圳         |
+----+-----------+--------------+
2 rows in set (0.00 sec)

-- 然后创建员工表,添加外键约束
mysql> CREATE TABLE employee (
    -> id INT PRIMARY KEY AUTO_INCREMENT,
    -> NAME VARCHAR(20),
    -> age INT,
    -> dep_id INT,
    -> -- 添加一个外键
    -> -- 外键取名公司要求,一般fk结尾
    -> CONSTRAINT emp_depid_ref_dep_id_fk FOREIGN KEY(dep_id) REFERENCES department(id)
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> 
正常添加数据
代码语言:javascript
复制
INSERT INTO employee (NAME, age, dep_id) VALUES
('张三', 20, 1),
('李四', 21, 1),
('王五', 20, 1),
('老王', 20, 2),
('大王', 22, 2),
('小王', 18, 2);

执行如下:

代码语言:javascript
复制
-- 插入数据到 employee
mysql> INSERT INTO employee (NAME, age, dep_id) VALUES
    -> ('张三', 20, 1),
    -> ('李四', 21, 1),
    -> ('王五', 20, 1),
    -> ('老王', 20, 2),
    -> ('大王', 22, 2),
    -> ('小王', 18, 2);
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

-- 查看 employee 表数据
mysql> select * from employee;
+----+--------+------+--------+
| id | NAME   | age  | dep_id |
+----+--------+------+--------+
|  1 | 张三   |   20 |      1 |
|  2 | 李四   |   21 |      1 |
|  3 | 王五   |   20 |      1 |
|  4 | 老王   |   20 |      2 |
|  5 | 大王   |   22 |      2 |
|  6 | 小王   |   18 |      2 |
+----+--------+------+--------+
6 rows in set (0.00 sec)

mysql> 
部门错误的数据添加失败
代码语言:javascript
复制
INSERT INTO employee (NAME, age, dep_id) VALUES ('二王', 20, 5);

执行如下:

代码语言:javascript
复制
mysql> select * from department;
+----+-----------+--------------+
| id | dep_name  | dep_location |
+----+-----------+--------------+
|  1 | 研发部    | 广州         |
|  2 | 销售部    | 深圳         |
+----+-----------+--------------+
2 rows in set (0.00 sec)

-- 可以发现插入的数据外键 dep_id=5, 而 department 表并没有 dep_id=5 的数据。
mysql> INSERT INTO employee (NAME, age, dep_id) VALUES ('二王', 20, 5);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`db1`.`employee`, CONSTRAINT `emp_depid_ref_dep_id_fk` FOREIGN KEY (`dep_id`) REFERENCES `department` (`id`))
mysql> 

5.3 删除外键(了解)

ALTER TABLE 从表 drop foreign key 外键名称;

具体操作:

  • 删除employee表的emp_depid_ref_dep_id_fk外键
代码语言:javascript
复制
ALTER TABLE employee DROP FOREIGN KEY emp_depid_ref_dep_id_fk;
  • 在employee表存在况下添加外键
代码语言:javascript
复制
ALTER TABLE employee ADD CONSTRAINT emp_depid_ref_dep_id_fk FOREIGN KEY(dep_id) REFERENCES department(id);

执行如下:

代码语言:javascript
复制
-- 查看当前 employee 的表结构
mysql> show create table employee;
+----------+-----------------------+
| Table    | Create Table          |
+----------+-----------------------+
| employee | CREATE TABLE `employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `NAME` varchar(20) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `dep_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `emp_depid_ref_dep_id_fk` (`dep_id`),
  CONSTRAINT `emp_depid_ref_dep_id_fk` FOREIGN KEY (`dep_id`) REFERENCES `department` (`id`) -- 外键
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 |
+----------+-----------------------+
1 row in set (0.00 sec)

-- 删除外键 emp_depid_ref_dep_id_fk
mysql> ALTER TABLE employee DROP FOREIGN KEY emp_depid_ref_dep_id_fk;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

-- 查看删除外键后的 employee
mysql> show create table employee;
+----------+------------------------+
| Table    | Create Table           |
+----------+------------------------+
| employee | CREATE TABLE `employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `NAME` varchar(20) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `dep_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `emp_depid_ref_dep_id_fk` (`dep_id`) -- 外键已经被删除了
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 |
+----------+-------------------------+
1 row in set (0.00 sec)

-- 在employee表存在况下添加外键
mysql> ALTER TABLE employee ADD CONSTRAINT emp_depid_ref_dep_id_fk FOREIGN KEY(dep_id) REFERENCES department(id);
Query OK, 6 rows affected (0.34 sec)
Records: 6  Duplicates: 0  Warnings: 0

-- 查看当前employee结构
mysql> show create table employee;
+----------+----------------------+
| Table    | Create Table         |
+----------+----------------------+
| employee | CREATE TABLE `employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `NAME` varchar(20) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `dep_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `emp_depid_ref_dep_id_fk` (`dep_id`),
  CONSTRAINT `emp_depid_ref_dep_id_fk` FOREIGN KEY (`dep_id`) REFERENCES `department` (`id`) -- 重新添加的外键
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 |
+----------+-----------------------+
1 row in set (0.00 sec)

mysql> 

5.4 数据操作注意事项

代码语言:javascript
复制
添加数据时:
 先添加主表中的数据,再添加从表中的数据
删除数据时:
 先删从表中的数据,再删主表中的数据
修改数据时:
 如果主表中的主键被从表引用了,不能修改此主键的值
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-02-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 海洋的渔夫 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 11. 多表间的关系-一对多-多对多-一对一-外键约束
    • 1. 表关系概述
      • 2. 一对多
        • 3. 多对多
          • 4. 一对一
            • 5. 外键约束
              • 5.1 什么是外键约束
              • 5.2 创建外键
              • 5.3 删除外键(了解)
              • 5.4 数据操作注意事项
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档