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图给出结构,数据字典给出字段级规则。以下为批次主表与库存表的核心字段定义,可直接作为建表与评审依据。
| 表 | 字段 | 类型 | 约束与说明 |
|---|---|---|---|
| batch | batch_no | VARCHAR(32) | 主键,全局唯一,按规则生成 |
| batch | material_code | VARCHAR(24) | 外键,非空,关联物料表 |
| batch | production_date | DATE | 非空,不得晚于当前日期 |
| batch | shelf_life_days | INT | 非空,大于0,默认取物料标准值 |
| batch | expiry_date | DATE | 非空,=生产日期+保质期,建索引 |
| batch | supplier_batch_no | VARCHAR(40) | 可空,外购品必填 |
| batch | qc_status | ENUM | 待检/合格/不合格/冻结,默认待检 |
| stock | stock_id | BIGINT | 主键,自增 |
| stock | batch_no | VARCHAR(32) | 外键,非空 |
| stock | location_code | VARCHAR(20) | 外键,非空 |
| stock | qty | DECIMAL(12,3) | 非空,不小于0 |
| stock | stock_status | ENUM | 可用/冻结/待检/锁定 |
约束设计上有两个易错点。其一,失效日期不要用生成列实时计算,因为保质期可能因工艺调整而变更,历史批次应保留入库时的计算结果,避免追溯时口径漂移。其二,库存状态与批次质检状态要区分:批次质检状态描述“这批货整体质量结论”,库存状态描述“当前这批货在该库位的可用性”,后者可因拣货锁定、盘点冻结而临时变化,二者不可合并。
四、一个入库示例
假设物料 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盒,库存状态“待检”。质检合格后,批次状态改为“合格”,库存状态改为“可用”,该批次才进入出库分配池。若质检不合格,则批次置“不合格”,库存置“冻结”,并触发隔离移库任务。整个过程体现了字段之间的联动:状态一变,可用量口径随之变化,而效期字段始终稳定,供预警与先进先出排序使用。