服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|数据库技术|

服务器之家 - 数据库 - Mysql - 细说 MySQL 的三种表关联设计

细说 MySQL 的三种表关联设计

2024-04-01 15:15java小白翻身 Mysql

正常两张表进行关联,我们可以采用中间表的方式,这是最灵活的方式,它可以直接将两张表的数据根据某个字段直接关联起来。

细说 MySQL 的三种表关联设计

一、通过关联表(N-N)

正常两张表进行关联,我们可以采用中间表的方式,这是最灵活的方式,它可以直接将两张表的数据根据某个字段直接关联起来。

下面是一个简单的例子来解释这个概念: 假设我们有两个表:students(学生)和 courses(课程)。一个学生可以选修多门课程,同时一门课程也可以被多个学生选修。这就是一个典型的多对多关系。

1.students 表

细说 MySQL 的三种表关联设计

2.courses 表

细说 MySQL 的三种表关联设计

为了表示学生和课程之间的多对多关系,我们可以使用一个中间表 student_courses:

3.student_courses 表

细说 MySQL 的三种表关联设计

在这个中间表中,每一行都表示一个学生和一门课程之间的关联。例如,第一行表示 Alice(学生ID为1)选修了 Math(课程ID为1)。 通过查询这个中间表,我们可以轻松地获取某个学生选修的所有课程,或者获取选修了某门课程的所有学生。 这种使用中间表的方式非常灵活,因为它允许我们轻松地添加、删除或修改学生和课程之间的关联,而不需要修改原始的 students 或 courses 表。

二、主从设计(1-N)

除了上面那种方式,还有一种主从设计,就是一张主表,一张明细表(或者叫做从表)。

主从设计或称为父子表设计是数据库中常见的另一种表关联方式。在这种设计中,主表通常存储主要实体的信息,而明细表或从表则存储与主表实体相关的详细或子项信息。这种设计常用于一对多关系,即一个主表记录对应多个明细表记录。 以下是一个主从设计的例子:

1.主表:orders(订单)

order_id

customer_id

order_date

total_amount

1

101

2023-04-01

100.00

2

102

2023-04-02

150.00

2.明细表:order_items(订单项)

item_id

order_id

product_id

quantity

unit_price

1

1

1001

2

50.00

2

1

1002

1

20.00

3

2

1003

3

50.00

在这个例子中:

  • orders 表是主表,它存储了订单的基本信息,如订单ID、客户ID、订单日期和总金额。
  • order_items 表是明细表或从表,它存储了每个订单的详细项,如订单项ID、所属的订单ID、产品ID、数量和单价。

通过 order_id 字段,order_items 表与 orders 表建立了关联。这样,我们可以轻松地查询某个订单的所有项,或者查询某个产品的所有订单项。 主从设计的优点是:

  • 结构清晰:主表和明细表各司其职,主表存储总体信息,明细表存储详细信息。
  • 灵活扩展:如果需要添加更多的与主表相关的详细信息,可以在明细表中添加更多字段,而不会影响主表的结构。
  • 易于维护:由于主表和明细表是分离的,所以对其中一个表的修改不会影响到另一个表。

需要注意的是,在设计数据库时,应根据实际业务需求和数据关系来选择合适的表关联方式。有时,可能需要结合使用中间表、主从设计或其他设计模式来满足复杂的业务需求。

三、关联设计(1-N)

除了上面说的主从设计,还有一些情况,就是两张表并非主从关系,但是也有一定的逻辑关联性。比如一个手机生产订单,我们要根据这个订单生成一个多个工单,分为原料采购工单,组装工单,包装工单等。这种也是一对多的关系,但并非主从关系,针对这种情况,我们需要做关联设计。

我们可以为手机订单表和工单表创建相应的数据库表结构,并模拟一些基础数据。以下是使用SQL语言创建表和插入数据的示例:

  1. 创建手机订单表 (phone_orders)
CREATE TABLE phone_orders (  
    sid INT PRIMARY KEY NOT NULL,  
    phone_name VARCHAR(100) NOT NULL,  
    phone_quantity INT NOT NULL  
);
  1. 创建工单表 (work_orders)

CREATE TABLE work_orders (  
    sid INT PRIMARY KEY NOT NULL,  
    sSrcSlaveId INT NOT NULL, -- 源单号,即手机订单表的sid  
    dProductPQty INT NOT NULL, -- 产品数量  
    FOREIGN KEY (sSrcSlaveId) REFERENCES phone_orders(sid) ON DELETE CASCADE  
);

这里,我们为work_orders表的sSrcSlaveId字段设置了外键约束,以确保它引用的是phone_orders表中存在的sid。使用ON DELETE CASCADE选项意味着当删除一个手机订单时,与该订单相关联的所有工单也会被自动删除。

3. 模拟基础数据

首先,向手机订单表中插入一些数据:

INSERT INTO phone_orders (sid, phone_name, phone_quantity) VALUES  
(1, 'iPhone 13', 0),  
(2, 'Galaxy S22', 0),  
(3, 'Pixel 6', 0);

然后,向工单表中插入与手机订单相关联的数据:

INSERT INTO work_orders (sid, sSrcSlaveId, dProductPQty) VALUES  
(1, 1, 20), -- 对应phone_orders中sid为1的订单,产品数量为20  
(2, 1, 30), -- 同一个订单的另一个工单,产品数量为30  
(3, 2, 50), -- 对应phone_orders中sid为2的订单,产品数量为50

这里的sid字段在两张表中都是唯一的,但在各自的表中可以重复。对于work_orders表,sSrcSlaveId字段对应于phone_orders表的sid,用于表示工单与哪个手机订单相关联。 手机订单的总数量为0,我们一般需要在生成工单的时候,去回填订单表的数量字段,这是很常见的需求。 尝试写sql如下:

update phone_orders A join (
 SELECT sSrcSlaveId,SUM(dProductPQty) dProductPQty from work_orders GROUP BY  sSrcSlaveId
) B on A.sid = B.sSrcSlaveId
set A.phone_quantity = B.dProductPQty
where  A.sid = 1;

基于您提供的SQL更新语句,这条语句的目的是更新phone_orders表中sid为1的记录,将其phone_quantity字段设置为与该订单相关联的所有工单的产品数量之和。

首先,我们来分析这条SQL语句的各个部分:

4.子查询:

SELECT sSrcSlaveId, SUM(dProductPQty) dProductPQty 
FROM work_orders 
GROUP BY sSrcSlaveId

这个子查询从work_orders表中选取sSrcSlaveId(即源单号,对应于phone_orders表的sid)和每个源单号对应的所有工单的产品数量之和(通过SUM(dProductPQty)计算)。结果集包含两列:sSrcSlaveId和计算后的产品数量dProductPQty。

5.JOIN操作:

UPDATE phone_orders A 
JOIN (
    ...子查询...
) B 
ON A.sid = B.sSrcSlaveId

这里使用了JOIN操作来连接phone_orders表(别名为A)和子查询的结果集(别名为B)。连接条件是A.sid = B.sSrcSlaveId,即phone_orders表的唯一键sid与子查询结果集中的sSrcSlaveId相匹配。

6.SET操作:

SET A.phone_quantity = B.dProductPQty

此部分将phone_orders表(别名为A)中的phone_quantity字段更新为子查询结果集(别名为B)中对应的dProductPQty值。

7.WHERE条件:

WHERE A.sid = 1

这个条件限制了更新的范围,只更新phone_orders表中sid为1的记录。

这条SQL语句的作用是:找出所有与phone_orders表中sid为1的订单相关联的工单,计算这些工单的产品数量之和,然后将phone_orders表中sid为1的记录的phone_quantity字段更新为这个总和。

执行后得到结果:

细说 MySQL 的三种表关联设计

思考题

上面的例子,如果我们换成left join,并且去查询A.sid = 3会发生什么?

update phone_orders A left join (
 SELECT sSrcSlaveId,SUM(dProductPQty) dProductPQty from work_orders GROUP BY  sSrcSlaveId
) B on A.sid = B.sSrcSlaveId
set A.phone_quantity = B.dProductPQty
where  A.sid = 3;

原文地址:https://mp.weixin.qq.com/s?__biz=MzI1ODI1ODkzMA==&mid=2247494505&idx=1&sn=8f0fc6eab37161f328bfe827fd1357ed

延伸 · 阅读

精彩推荐
  • MysqlMySQL 快速删除大量数据(千万级别)的几种实践方案详解

    MySQL 快速删除大量数据(千万级别)的几种实践方案详解

    这篇文章主要介绍了MySQL 快速删除大量数据(千万级别)的几种实践方案详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考...

    CoderBaby4852021-01-23
  • MysqlMySQL中的redo log和undo log日志详解

    MySQL中的redo log和undo log日志详解

    MySQL日志系统中最重要的日志为重做日志redo log和归档日志bin log,后者为MySQL Server层的日志,前者为InnoDB存储引擎层的日志。今天通过本文给大家介绍MySQ...

    pedro711172021-09-02
  • MysqlWindows10 64位安装MySQL5.6.35的图文教程

    Windows10 64位安装MySQL5.6.35的图文教程

    这篇文章主要介绍了Windows10 64位安装MySQL5.6.35的图文教程,非常不错,具有参考借鉴价值,需要的朋友可以参考下 ...

    此城以空3862020-07-18
  • MysqlMySQL多版本并发控制MVCC深入学习

    MySQL多版本并发控制MVCC深入学习

    这篇文章主要介绍了MySQL多版本并发控制MVCC,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    CJ-cooper5612022-01-12
  • Mysqlmysql 联合索引生效的条件及索引失效的条件

    mysql 联合索引生效的条件及索引失效的条件

    两个或更多个列上的索引被称作复合索引,本文主要介绍了mysql 联合索引生效的条件及索引失效的条件,感兴趣的可以了解一下...

    smileTimLi4742021-12-07
  • MysqlMySQL 5.6 GTID新特性实践

    MySQL 5.6 GTID新特性实践

    GTID(Global Transaction ID)是对于一个已提交事务的编号,并且是一个全局唯一的编号。下文给大家介绍MySQL 5.6 GTID新特性实践,感兴趣的朋友一起看看吧 ...

    MYSQL教程网2302020-06-27
  • MysqlMySQL数据库索引的最左匹配原则

    MySQL数据库索引的最左匹配原则

    sql查询用到索引的条件是必须要遵守最左前缀原则,本文就详细的介绍了MySQL数据库索引的最左匹配原则,感兴趣的可以了解一下...

    风幕浦8242021-12-07
  • Mysql详解隐秘的 MySQL 类型转换问题详解

    详解隐秘的 MySQL 类型转换问题详解

    这篇文章主要为大家介绍了详解隐秘的 MySQL 类型转换问题详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪...

    架构精进之路3532022-11-24