3. 食品保质期数据模型设计

保质期预警系统能否算得准、报得及时,取决于底层数据模型是否把“时间”这件事表达清楚。很多项目上线后预警频繁误报或漏报,追根溯源往往不是算法问题,而是数据模型里只有一个模糊的“保质期天数”,缺少批次粒度、缺少到期日期、缺少可比较的库龄口径。本节围绕一个可落地的保质期数据模型展开,把 SKU、批次、生产日期、到期日期、剩余保质期、库龄与预警状态这七个核心对象的定义、来源与计算关系讲清楚。

一、先分清两类字段:静态主数据与动态计算字段

设计数据模型的第一步不是急着建表,而是给每个字段定性。SKU 层面的保质期规则属于静态主数据,变更频率低,由商品档案维护;批次层面的生产日期、到期日期属于业务事实数据,随每次入库产生;剩余保质期、库龄、预警状态则属于动态计算字段,它们不应被当作手工录入值长期存储,而应由系统按统一口径实时或定时计算得出。把这三类混在一起,是后续口径混乱的主要根源。

具体来说,SKU 主数据至少需要承载:保质期天数(或保质期月数)、是否允许按天精确计算、预警阈值规则(如剩余保质期占比低于 1/3 触发黄色预警、低于 1/6 触发红色预警)、是否启用批次管理。批次数据则承载:批次号、生产日期、到期日期、入库日期、当前库存数量、库位。计算字段承载:剩余保质期天数、剩余保质期占比、库龄天数、预警状态。下面这张图展示了各字段之间的依赖与计算链路。

SKU 主数据(静态) SKU 编码 / 名称 保质期天数(如 180 天) 预警阈值规则(1/3、1/6) 是否批次管理 存储条件(常温/冷藏) 批次数据(事实) 批次号(如 B20250312-01) 生产日期 到期日期 入库日期 当前库存数量 / 库位 关联 SKU 编码 动态计算字段 剩余保质期天数 = 到期日期 − 当前日期 剩余保质期占比 = 剩余天数 ÷ 保质期天数 库龄天数 = 当前日期 − 入库日期 预警状态 正常 / 黄色 / 红色 / 已过期 由占比与阈值规则判定 预警输出 预警等级 触发时间 建议处置(先出/促销) 通知对象(库管/采购) 处理状态(待办/已办) 提供保质期天数 提供日期与库存 判定结果 口径约定:所有天数按自然日计算,当前日期取系统日期;到期日期 = 生产日期 + 保质期天数 − 1(含生产当日)

二、关键字段的定义与计算口径

SKU 编码是主数据主键,保质期天数以它为准。需要注意“保质期月数”与“天数”的换算问题:若商品标注“保质期 6 个月”,不能简单按 180 天处理,应按生产日期加 6 个自然月再减 1 天得到到期日期,否则跨月长度不同会造成偏差。建议在 SKU 主数据中同时保留“保质期单位(天/月)”字段,由系统按单位分别计算。

批次号是保质期管理的实际粒度。同一 SKU 不同批次的生产日期不同,到期日期也不同,预警必须落到批次上,否则无法指导“先出哪个批次”。批次号建议采用“生产日期 + 流水号”的可读编码,如 B20250312-01,便于人工核对。

生产日期与到期日期是一对强关联字段。到期日期可以由生产日期加保质期推算,但更稳妥的做法是入库时同时记录两者并做一致性校验:若供应商提供的到期日期与推算值偏差超过 1 天,应标记为“日期待核实”,避免因标签印刷差异或录入错误导致预警失真。对于进口食品,还需注意保质期标注格式差异(如“Best Before”日期)。

剩余保质期建议同时保留两个值:剩余天数与剩余占比。剩余天数 = 到期日期 − 当前日期;剩余占比 = 剩余天数 ÷ 保质期天数。仅看天数不够——保质期 7 天的鲜奶剩 2 天已很危险,而保质期 365 天的罐头剩 2 天同样危险但剩 60 天时却完全正常,占比能统一不同保质期长度的商品口径。

库龄是常被忽略但极有价值的字段。库龄天数 = 当前日期 − 入库日期。它与剩余保质期并不等价:一批货可能生产很早但入库很晚(如调拨、退货再入库),此时库龄短而剩余保质期短,说明该批次在流通环节已消耗大量时间,应优先处理。库龄还用于分析仓储周转效率,与预警状态配合可区分“临期但刚入库”和“临期且长期积压”两类问题。

预警状态是计算字段的最终输出,建议采用四态:正常、黄色预警、红色预警、已过期。判定逻辑基于剩余占比与 SKU 阈值规则,例如占比 ≤ 1/3 且 > 1/6 为黄色,≤ 1/6 且 > 0 为红色,≤ 0 为已过期。状态应由系统按日批量重算,而不是在查询时临时判断,以保证预警记录可追溯、可统计。

三、一个可参考的字段定义表

下表给出可直接用于建表或配置的字段清单,字段类型与示例值均为教学示例,实际项目应按所用数据库与业务规模调整。

字段所属对象类型示例值说明
sku_codeSKU字符串SKU-10086主数据主键
shelf_life_valueSKU整数180保质期数值
shelf_life_unitSKU枚举天天 / 月
warn_ratio_yellowSKU小数0.333黄色预警占比阈值
warn_ratio_redSKU小数0.167红色预警占比阈值
batch_no批次字符串B20250312-01批次唯一标识
produce_date批次日期2025-03-12生产日期
expire_date批次日期2025-09-07到期日期
inbound_date批次日期2025-03-20入库日期
remain_days计算整数45剩余保质期天数
remain_ratio计算小数0.25剩余保质期占比
stock_age_days计算整数37库龄天数
warn_status计算枚举黄色预警正常/黄色/红色/已过期

四、用示例数据走一遍计算

假设某常温酸奶 SKU-10086,保质期 180 天,黄色阈值 1/3、红色阈值 1/6。批次 B20250312-01 生产日期 2025-03-12,到期日期按“生产日期 + 180 − 1”推算为 2025-09-07,入库日期 2025-03-20。若当前日期为 2025-07-25,则:

剩余保质期天数 = 2025-09-07 − 2025-07-25 = 44 天
剩余保质期占比 = 44 ÷ 180 ≈ 0.244
库龄天数       = 2025-07-25 − 2025-03-20 = 127 天
预警判定       = 0.244 ≤ 1/3 且 > 1/6 → 黄色预警

此时系统应输出黄色预警,并建议“优先出库、安排促销”。若再过 15 天,剩余占比降至约 0.161,低于 1/6,状态自动升级为红色预警。可以看到,同一批次的状态是随日期推移而变化的,这正是预警状态必须由系统按日重算、而不能人工维护的原因。

设计建议:把“到期日期”作为批次表的核心冗余字段存储,而不是每次查询都实时用生产日期加保质期推算。原因是 SKU 保质期规则可能被修订,若历史批次实时推算,规则一改历史批次的到期日期会跟着变,导致预警记录前后不一致。入库时固化到期日期,才能保证数据可追溯。
常见误区:只建 SKU 级保质期字段而不建批次表。这样系统只能回答“这个商品保质期多久”,无法回答“仓库里哪一批快到期了”,预警就失去了执行价值。只要涉及实物库存管理,批次粒度就是底线要求。

最后需要强调口径一致性:剩余保质期、库龄、预警判定必须共用同一个“当前日期”基准,且明确是否含当日。建议在系统配置中统一约定“到期日期当天仍可销售,次日起视为已过期”,并在所有计算与报表中沿用,避免库管看到的剩余天数与预警模块相差一天而引发争议。数据模型的价值不在于字段多,而在于每个字段的定义唯一、来源清晰、计算可复现。