2. 食品批次数据模型设计

在食品WMS中,批次不是一个孤立的字符串,而是一组围绕“可追溯、可隔离、可先出”目标组织起来的主数据。批号只是它的对外标识,真正决定系统行为的,是生产日期、保质期、失效日期、供应商批次、质检状态等字段共同构成的“时间—质量—来源”三维属性。设计数据模型时,如果只把批号挂在库存表上,后续的效期预警、先进先出、质量冻结、召回追溯都会缺少落点。因此本节从批次主数据字段出发,逐步理清批次与物料、库位、库存三者的关联关系,并给出可落地的ER结构与数据字典。

一、批次主数据字段的取舍

批次主数据首先要回答三个问题:这批货是什么、什么时候到期、质量是否可用。围绕这三点,核心字段可以归纳如下。

  • 批号(batch_no):企业内部唯一标识,建议按“物料编码+生产日期+产线/班次+流水”规则生成,例如 FG-20240518-A-01,保证可读且可检索。
  • 物料编码(material_code):批次必须归属到一个物料,物料决定计量单位、存储条件(常温/冷藏/冷冻)与保质期基准。
  • 生产日期(production_date):效期计算的起点,也是先进先出的排序依据。
  • 保质期(shelf_life_days):以天为单位的时长,来源于物料标准或供应商声明。
  • 失效日期(expiry_date):由生产日期加保质期推导,是系统判断可售与否的直接依据,必须落库而非每次实时计算,便于索引与预警。
  • 供应商批次(supplier_batch_no):原料或外购品用于对接上游追溯,与内部批号分离,避免供应商换批导致内部编码混乱。
  • 质检状态(qc_status):至少包含待检、合格、不合格、冻结四态,直接控制该批次能否参与出库分配。

需要强调的是,失效日期与质检状态是“会变化或会被频繁查询”的字段,前者应在入库时一次算好并建立索引,后者应作为库存可用量计算的过滤条件,而不是仅作展示。

二、批次与物料、库位、库存的关联关系

四者关系可以用一句话概括:物料定义“是什么”,批次定义“哪一批”,库位定义“放在哪”,库存记录定义“有多少、处于什么状态”。具体关联如下。

  • 物料—批次(1:N):一个物料可对应多个批次,批次必须且只能属于一个物料。物料上的保质期、存储条件是批次的默认来源。
  • 批次—库存(1:N):同一批次可能分散在多个库位,因此库存记录以“物料+批次+库位+库存状态”为粒度,而不是批次直接持有数量。
  • 库位—库存(1:N):一个库位可存放多个批次,库存表通过库位编码关联到具体货架或储区。
  • 批次—库位(M:N,经由库存):批次与库位之间不直接建外键,而是通过库存记录这一关联实体连接,这样同一批次跨库位存放时不会产生数据冗余。

这种设计的直接好处是:查询“某批次还剩多少可用”时,只需按批次聚合库存表中状态为可用的记录;查询“某库位有哪些临期批次”时,按库位过滤再关联批次效期即可,两条高频路径都不需要跨表拼接过多。

食品批次数据模型 ER 关系示意 物料 Material PK material_code material_name shelf_life_days storage_condition unit 批次 Batch PK batch_no FK material_code production_date expiry_date supplier_batch_no qc_status 库存 Stock PK stock_id FK batch_no FK location_code qty / stock_status inbound_date 库位 Location PK location_code zone / aisle temp_zone capacity 1 : N 1 : N N : 1 关联要点 · 批次必须归属唯一物料 · 批次与库位经库存表连接 · 库存粒度=物料+批次+库位+状态 · 失效日期入库时计算并建索引 · 质检状态过滤可用库存 · 供应商批次独立于内部批号

三、数据字典与关键约束

ER图给出结构,数据字典给出字段级规则。以下为批次主表与库存表的核心字段定义,可直接作为建表与评审依据。

表字段类型约束与说明
batchbatch_noVARCHAR(32)主键,全局唯一,按规则生成
batchmaterial_codeVARCHAR(24)外键,非空,关联物料表
batchproduction_dateDATE非空,不得晚于当前日期
batchshelf_life_daysINT非空,大于0,默认取物料标准值
batchexpiry_dateDATE非空,=生产日期+保质期,建索引
batchsupplier_batch_noVARCHAR(40)可空,外购品必填
batchqc_statusENUM待检/合格/不合格/冻结,默认待检
stockstock_idBIGINT主键,自增
stockbatch_noVARCHAR(32)外键,非空
stocklocation_codeVARCHAR(20)外键,非空
stockqtyDECIMAL(12,3)非空,不小于0
stockstock_statusENUM可用/冻结/待检/锁定

约束设计上有两个易错点。其一,失效日期不要用生成列实时计算,因为保质期可能因工艺调整而变更,历史批次应保留入库时的计算结果,避免追溯时口径漂移。其二,库存状态与批次质检状态要区分:批次质检状态描述“这批货整体质量结论”,库存状态描述“当前这批货在该库位的可用性”,后者可因拣货锁定、盘点冻结而临时变化,二者不可合并。

四、一个入库示例

假设物料 FG-YOGURT-500 为冷藏酸奶,保质期21天,存储条件2~6℃。2024年5月18日入库一批,产线A班次,则批号可生成 FG-YOGURT-500-20240518-A-01,生产日期2024-05-18,失效日期2024-06-08,供应商批次 SUP-2405-771,质检状态初始为“待检”。此时库存记录写入库位 CL-01-03,数量1200盒,库存状态“待检”。质检合格后,批次状态改为“合格”,库存状态改为“可用”,该批次才进入出库分配池。若质检不合格,则批次置“不合格”,库存置“冻结”,并触发隔离移库任务。整个过程体现了字段之间的联动:状态一变,可用量口径随之变化,而效期字段始终稳定,供预警与先进先出排序使用。

建模评审时可用三个问题自检:能否按批次查到全部存放库位?能否按库位筛出临期批次?能否在不改历史数据的前提下追溯供应商批次?三问皆可,模型基本可用。