4. BOM 数据模型:数据库表结构设计与关键字段解析

BOM(Bill of Materials,物料清单)是 MRP 运算的核心数据基础。一个设计良好的 BOM 数据模型,需要准确表达物料之间的父子层级关系、装配数量、时间有效性等关键维度。本章从数据库表结构设计出发,详细解析 BOM 的核心字段及其在 MRP 计算中的映射逻辑。

4.1 BOM 核心数据库表结构

在 ERP 系统中,BOM 通常采用“主表 + 子表”的经典设计模式。主表存储 BOM 头信息(如 BOM 编号、版本、生效日期),子表存储具体的物料组成明细(如子件物料、数量、工序)。

表名 说明 核心字段
BOM_HEADER BOM 主表,记录 BOM 版本、状态、有效期 BOM_ID, ITEM_ID, BOM_NAME, VERSION, STATUS, EFF_DATE, EXP_DATE, CREATE_TIME
BOM_ITEM BOM 子表,记录每个子件物料及用量 BOM_ITEM_ID, BOM_ID, PARENT_ITEM_ID, CHILD_ITEM_ID, QUANTITY, SCRAP_PCT, OPS_SEQ, EFF_DATE, EXP_DATE
ITEM_MASTER 物料主文件,存储物料基础属性 ITEM_ID, ITEM_CODE, ITEM_NAME, UOM, ITEM_TYPE, LEAD_TIME, LOT_SIZE
设计要点:BOM_ITEM 表中的 PARENT_ITEM_ID 和 CHILD_ITEM_ID 共同构成父子关系字段,通过这两个字段可以递归展开任意层级的 BOM 结构。建议在数据库层面为这两个字段建立联合索引,以加速 MRP 的递归查询性能。

4.2 父子关系字段与层级结构

BOM 的父子关系通过 PARENT_ITEM_ID 和 CHILD_ITEM_ID 两个字段实现。一个父物料可以包含多个子物料,一个子物料也可以被多个父物料使用(多父项)。这种设计天然支持树形结构的递归展开。

以下是一个典型的 BOM 层级展开 SQL 示例(使用递归 CTE):

WITH RECURSIVE BOM_EXPLOSION AS (
  -- 根节点:查询顶层成品
  SELECT 
    bi.BOM_ID,
    bi.PARENT_ITEM_ID,
    bi.CHILD_ITEM_ID,
    bi.QUANTITY,
    1 AS LEVEL,
    CAST(bi.CHILD_ITEM_ID AS VARCHAR(500)) AS PATH
  FROM BOM_ITEM bi
  WHERE bi.PARENT_ITEM_ID = 'FG-001'  -- 顶层成品物料编码
    AND bi.EFF_DATE <= CURRENT_DATE
    AND bi.EXP_DATE >= CURRENT_DATE

  UNION ALL

  -- 递归展开:查询子件的下一级
  SELECT 
    bi.BOM_ID,
    bi.PARENT_ITEM_ID,
    bi.CHILD_ITEM_ID,
    bi.QUANTITY * be.QUANTITY AS QUANTITY,
    be.LEVEL + 1,
    be.PATH || '->' || CAST(bi.CHILD_ITEM_ID AS VARCHAR(500))
  FROM BOM_ITEM bi
  INNER JOIN BOM_EXPLOSION be ON bi.PARENT_ITEM_ID = be.CHILD_ITEM_ID
  WHERE bi.EFF_DATE <= CURRENT_DATE
    AND bi.EXP_DATE >= CURRENT_DATE
)
SELECT * FROM BOM_EXPLOSION ORDER BY PATH;
关键说明:上述递归查询中,LEVEL 字段标识物料在 BOM 中的层级深度(顶层为 1),PATH 字段记录从顶层到当前物料的完整路径,便于 MRP 计算时进行多层级需求汇总。

4.3 数量关系字段与用量计算

BOM 子表中的 QUANTITY 字段定义了生产一个单位父物料所需消耗的子物料数量。在 MRP 计算中,数量关系是需求展开的核心参数。

字段名 数据类型 说明 示例
QUANTITY DECIMAL(18,6) 生产一个单位父物料所需子物料的数量 2.000000(表示需要 2 个)
SCRAP_PCT DECIMAL(5,2) 子物料在生产过程中的损耗百分比 5.00(表示 5% 损耗)
USAGE_TYPE VARCHAR(10) 用量类型:固定用量 / 变动用量 FIXED / VARIABLE

MRP 在计算毛需求时,会按照以下公式进行数量展开:

毛需求数量 = 父物料计划数量 × QUANTITY × (1 + SCRAP_PCT / 100)
常见误区:部分系统将 SCRAP_PCT 直接加在 QUANTITY 上,导致 MRP 计算结果偏大。正确的做法是:SCRAP_PCT 作为独立因子参与计算,且仅在父物料层级累加,避免在递归展开时重复计算损耗。

4.4 生效/失效日期与版本控制

BOM 的生效日期(EFF_DATE)和失效日期(EXP_DATE)是 MRP 计算中时间维度的关键约束。通过日期字段,ERP 系统可以支持 BOM 的工程变更(ECO)、版本切换和临时替代。

日期字段的设计原则:

  • 生效日期(EFF_DATE):BOM 版本开始使用的日期,MRP 计算时只考虑生效日期 ≤ 计划日期的 BOM。
  • 失效日期(EXP_DATE):BOM 版本停止使用的日期,MRP 计算时只考虑失效日期 ≥ 计划日期的 BOM。
  • 版本号(VERSION):配合日期字段使用,同一物料可以有多个版本的 BOM,但同一时间只能有一个生效版本。
  • 替代 BOM:通过设置不同的生效日期范围,实现临时替代或并行生产。
最佳实践:建议在 BOM_HEADER 和 BOM_ITEM 两个表中都保留 EFF_DATE 和 EXP_DATE 字段。BOM_HEADER 的日期控制整个 BOM 版本的可用性,BOM_ITEM 的日期则支持单个子件的临时替换(如供应商切换、物料淘汰)。MRP 计算时,两个表的日期条件需同时满足。

4.5 BOM 数据模型整体架构

下图展示了 BOM 数据模型中各表之间的关联关系,以及核心字段在 MRP 计算中的流转路径。

BOM 数据模型核心表结构及字段关系 ITEM_MASTER 物料主文件 ITEM_ID (PK) ITEM_CODE ITEM_NAME LEAD_TIME, LOT_SIZE BOM_HEADER BOM 主表 BOM_ID (PK) ITEM_ID (FK → ITEM_MASTER) VERSION, STATUS EFF_DATE, EXP_DATE BOM_ITEM BOM 子表 BOM_ITEM_ID (PK) BOM_ID (FK → BOM_HEADER) PARENT_ITEM_ID (FK) CHILD_ITEM_ID (FK) QUANTITY, SCRAP_PCT OPS_SEQ, EFF_DATE, EXP_DATE ITEM_ID BOM_ID PARENT_ITEM_ID CHILD_ITEM_ID MRP 计算中的字段映射说明 1. 父子关系:PARENT_ITEM_ID + CHILD_ITEM_ID 构成 BOM 树形结构的递归基础 2. 数量关系:QUANTITY 字段决定 MRP 展开时的倍数因子,SCRAP_PCT 增加额外需求 3. 时间约束:EFF_DATE / EXP_DATE 控制 BOM 版本和子件替代的时间窗口 4. 层级展开:通过递归 CTE 或存储过程,按 LEVEL 逐层计算各层级物料需求 5. 版本控制:VERSION + STATUS 字段确保同一时间只有一个 BOM 版本生效 6. 多父项支持:同一 CHILD_ITEM_ID 可出现在多个 BOM 中,支持通用件管理

4.6 BOM 数据模型设计检查清单

在实施 BOM 数据模型时,建议对照以下清单进行设计评审:

检查项 说明 优先级
父子关系完整性 PARENT_ITEM_ID 和 CHILD_ITEM_ID 是否都引用了 ITEM_MASTER 表?是否建立了外键约束? 高
数量精度 QUANTITY 字段的数据类型是否支持足够的小数位数(建议 DECIMAL(18,6))? 高
日期索引 EFF_DATE 和 EXP_DATE 字段是否建立了索引?MRP 查询时是否使用了日期过滤? 高
递归查询性能 BOM 层级深度是否有限制?递归查询是否设置了最大递归深度(如 20 层)? 中
版本冲突检测 同一物料在同一时间点是否存在多个生效的 BOM 版本?是否有唯一性约束? 高
替代 BOM 支持 是否支持通过日期范围或优先级字段实现 BOM 的临时替代? 中
总结:BOM 数据模型是 MRP 计算的基石。一个健壮的 BOM 表结构设计,需要同时考虑父子关系的递归展开、数量关系的精确计算、时间维度的版本控制,以及数据库层面的查询性能优化。在实际 ERP 实施中,建议在 BOM_ITEM 表上建立 (PARENT_ITEM_ID, EFF_DATE, EXP_DATE) 的联合索引,以加速 MRP 的递归查询效率。