Skip to content

064. 中间表、ORM 关系与统计查询 ​

学习目标 ​

这一节把关联查询放回项目业务里,并引出 ORM 关系查询的取舍。

学完后,你应该能理解:

  • 项目成员为什么需要中间表;
  • 中间表和外键不是一回事;
  • 多对多关系如何增删;
  • 项目已花费金额可以如何统计;
  • ORM relationship 为什么像黑盒;
  • 为什么复杂查询最终仍然离不开 SQL。

项目成员关系 ​

项目和用户是多对多关系。

一个项目可以有多个成员。

一个用户也可以参与多个项目。

这种关系通常用中间表保存。

中间表里至少有:

  • 项目 ID;
  • 用户 ID。

这两列共同描述“哪个用户参与了哪个项目”。

中间表命名 ​

课程项目里,中间表会用固定前缀区分。

例如以 rel 开头,表示关系表。

这样看到表名时,就能快速判断它不是业务主表,而是用来描述对象关系的表。

查询项目成员 ​

查询某个项目的成员时,可以从中间表开始。

流程是:

  1. 按项目 ID 查询中间表;
  2. 拿到用户 ID;
  3. 关联用户表;
  4. 返回用户信息。

如果项目新增一个成员,本质上就是往中间表插入一条关系记录。

如果删除成员,本质上就是删除这条关系记录。

中间表可以有额外字段 ​

中间表不一定只有两个 ID。

如果关系本身也有信息,可以增加字段。

例如项目成员关系里可以记录:

  • 角色;
  • 职位;
  • 加入时间;
  • 权限级别。

这时中间表不仅表示“有关系”,还描述“是什么关系”。

中间表不是外键 ​

中间表和外键是两码事。

中间表用于描述两个业务对象之间的关系。

外键用于在数据库层面约束某个字段必须引用另一张表的合法记录。

可以有中间表但不建外键。

也可以没有中间表,但某个字段逻辑上指向另一张表。

为什么不强依赖数据库外键 ​

实际业务项目里,很多团队不会在数据库层面大量使用外键。

原因是外键会让删除、数据迁移、导入、批量修复变复杂。

课程项目把关系约束放在后端业务代码里处理。

这样应用逻辑更可控。

一对多字段关系 ​

不是所有关系都需要中间表。

例如项目表里有 leader_id。

它表示这个项目的负责人是谁。

一个项目只有一个负责人。

这种关系可以直接在项目表里保存用户 ID。

查询负责人时,用 leader_id 关联用户表即可。

项目花费金额 ​

项目表里可以存一个已花费金额字段。

但也可以不存。

如果不存,就通过审批单统计出来。

例如项目下有多张审批单,每张审批单有金额和状态。

只统计审批通过的审批单金额,求和后就是项目已花费金额。

这种方式避免了并发更新项目金额字段,但查询会更复杂。

报销单、审批单与项目 ​

项目、报销单、审批单之间有关系。

报销单会进入审批流程。

审批通过后,会产生或更新审批单状态。

审批单里保存项目 ID 和金额。

统计项目花费时,就按项目 ID 聚合审批单金额。

用 SQL 做统计 ​

统计查询适合直接写 SQL。

例如:

  • 按项目 ID 过滤;
  • 只统计审批通过的数据;
  • 对金额做 sum;
  • 按项目分组;
  • 返回项目与已花费金额。

SQL 写清楚后,逻辑是透明的。

你能看到每一步 join、where、group by 和聚合。

ORM relationship ​

SQLModel 这类 ORM 支持定义关系属性。

例如项目模型可以定义负责人关系。

用户模型也可以定义自己负责的项目列表。

查询时可以通过 relationship 预加载相关数据。

这样写起来很方便。

relationship 的黑盒感 ​

ORM 自动生成 SQL。

这带来便利,也带来黑盒感。

当关联层级多、表很多、数据量大时,你可能不知道它到底生成了什么 SQL。

如果 SQL 没走索引,或者查出了过多数据,性能问题会比较难排。

所以复杂查询不能完全依赖 ORM 自动关系。

手写 SQL 的必要性 ​

当项目里有统计、报表、多表聚合、动态查询时,最终还是要能写 SQL。

ORM 可以处理简单 CRUD。

复杂查询更需要你清楚地控制:

  • 查哪些字段;
  • join 哪些表;
  • 用哪些条件;
  • 是否命中索引;
  • 聚合和分组怎么做。

这也是为什么很多后端项目仍然保留大量手写 SQL。

后续封装方向 ​

课程后面会封装一个更适合项目的查询能力。

目标是兼顾:

  • ORM 的便利;
  • 手写 SQL 的可控;
  • 动态查询表达式;
  • 自动生成接口;
  • 热更新配置;
  • 测试保障。

也就是说,不是完全依赖 ORM,也不是每个接口都从零手写。

这一节的重点 ​

这一节把关联查询和业务表关系连接起来。

你需要记住:

  • 多对多通常用中间表;
  • 中间表和外键不是一回事;
  • 项目成员关系就是中间表记录;
  • 项目花费可以通过审批单聚合统计;
  • ORM relationship 方便但有黑盒风险;
  • 复杂统计查询最终还是要懂 SQL。

AI Agent 课程学习文档。