4. 查询应用的数据模型设计

要让《食品添加剂使用标准》从一本厚厚的表格变成可查询、可校验、可追溯的应用,第一步不是写界面,而是把标准里的“人话”翻译成“数据结构”。数据模型决定了后续查询能回答什么问题:能不能按食品类别反查允许使用的添加剂,能不能判断某条使用量是否超限,能不能区分“最大使用量”和“残留量”两种约束。本节围绕食品分类、添加剂、使用范围、最大使用量这几个核心实体,讲清楚它们的属性该怎么定、关联该怎么建。

一、先识别实体,再谈字段

从标准文本中抽取实体,最直接的方法是看“一句话里出现了哪几类名词”。以一条典型规定为例:“某防腐剂在酱腌菜中的最大使用量为0.5 g/kg”,其中出现了三个可独立管理的对象:添加剂(某防腐剂)、食品类别(酱腌菜)、使用规定(最大使用量0.5 g/kg)。这三者不是并列关系,而是“使用规定”把添加剂和食品类别连接起来,并携带了量化约束。因此数据模型的主干应是:添加剂与食品分类两个主数据实体,通过使用范围这一关联实体建立多对多关系,最大使用量则作为使用范围上的量化属性存在。

这里有一个容易踩的坑:把“最大使用量”单独做成一张表。单独建表并非不可,但若它只依附于某一条使用规定、没有独立生命周期,那么把它作为使用范围实体的字段更自然,查询时也少一次连接。只有当同一使用规定需要按不同食品子类分别给出不同限量时,才考虑拆出“限量明细”子表。

二、食品分类:树形结构与编码

食品分类是典型的层级数据,标准中通常采用“大类—亚类—次亚类—具体品种”的多级结构。建模时推荐使用邻接表:每个分类节点保存自身编码、名称、父节点编码和层级。这样既能表达树形,又便于递归查询“某大类下所有子类允许使用的添加剂”。

关键属性建议包括:分类编码(唯一、稳定、可排序)、分类名称、父级编码、层级深度、是否为叶子节点。编码设计要特别注意:标准修订时分类可能拆分或合并,因此编码不宜直接复用业务含义,而应保留版本字段,例如“分类编码+标准版本号”作为联合唯一键,避免新旧版本数据互相污染。

另一个实用设计是“分类路径”字段,把从根到当前节点的编码用分隔符拼成一串,例如“01/01.02/01.02.03”。这样查询某节点及其全部后代时,只需一次前缀匹配,不必递归,对查询性能非常友好。

三、添加剂:主数据与别名

添加剂实体的核心属性包括:添加剂编码(如CNS号或内部主键)、中文名称、英文名称、功能类别(防腐剂、着色剂、甜味剂等)、备注。功能类别建议单独建字典表,因为一种添加剂可能兼具多种功能,用多值关联比在添加剂表里塞一个字符串更规范。

标准中同一添加剂常有别名、商品名或旧称,查询应用必须支持“按别名也能查到”。因此需要一张添加剂别名表,字段为添加剂主键、别名、别名类型。这样用户输入“山梨酸钾”或某个旧称,都能命中同一主数据,避免重复建档。

四、使用范围与最大使用量:关联实体的字段设计

使用范围是连接添加剂与食品分类的桥梁,也是查询应用最常访问的表。它的关键属性包括:添加剂主键、食品分类编码、最大使用量数值、计量单位、约束类型、备注、标准版本。其中约束类型非常重要,至少要区分“最大使用量”“残留量”“按生产需要适量使用”三类,因为它们的判断逻辑完全不同:前两者是数值比较,后者是布尔型允许。

计量单位不能省略。标准中常见g/kg、mg/kg、g/L等,若统一换算成基准单位存储,查询展示时再换算回原单位,可避免“0.5 g/kg”和“500 mg/kg”被当成两个不同限量。建议在表中同时保留原始数值、原始单位和换算后的基准值,兼顾可读性与可比性。

下面这张图展示了四个核心实体及其关联关系,可作为建表时的参照:

食品分类 分类编码(PK) 分类名称 父级编码(FK自关联) 层级深度 / 分类路径 标准版本 添加剂 添加剂主键(PK) CNS号 / 中文名称 英文名称 功能类别(多值) 备注 使用范围(关联实体) 添加剂主键(FK) 食品分类编码(FK) 最大使用量数值 计量单位 / 基准值 约束类型(限量/残留/适量) 标准版本 添加剂别名 添加剂主键(FK) 别名 别名类型 1 : N 1 : N 1 : N(别名检索) 添加剂 × 食品分类 = 多对多,经使用范围拆解

五、从模型到查询:三个典型场景

模型是否合理,要看它能否顺畅支撑真实查询。第一个场景是“正向查询”:给定添加剂,列出其允许使用的食品类别及限量。这只需从使用范围表按添加剂主键过滤,再连接食品分类取名称,一次两表连接即可完成。

第二个场景是“反向查询”:给定食品类别,列出允许使用的全部添加剂。由于食品分类是树形,用户选“酱腌菜”时,往往也要看到其父类或子类下的规定。此时利用分类路径字段做前缀匹配,把目标节点及其后代一次性取出,再与使用范围关联,避免逐层递归。

第三个场景是“合规判断”:已知食品类别、添加剂和实际使用量,判断是否超限。查询先定位到对应使用范围记录,读取约束类型:若为“按生产需要适量使用”,直接判定允许;若为限量型,则把实际使用量换算到基准单位后与基准值比较。这里必须注意单位一致性,否则0.5 g/kg与500 mg/kg的比较会得出错误结论。

建模时给使用范围表加上“标准版本”字段,并在查询入口固定当前生效版本,可以避免新旧标准混查。标准换版时,旧版本数据保留、新版本数据新增,而不是原地覆盖,这样历史查询和追溯才有依据。

六、几个容易忽略的约束

第一,使用范围表应对“添加剂主键+食品分类编码+标准版本”建立唯一约束,防止同一规定被重复录入,导致查询结果出现重复行。第二,最大使用量字段允许为空,但空值必须与“按生产需要适量使用”区分开:前者表示该条记录不适用数值限量,后者是一种明确的约束类型,二者不能都用NULL表达。第三,食品分类的父级编码应允许为空,仅根节点为空,并加自关联外键约束,防止出现孤儿节点。

把这些实体、字段和约束落成表结构后,查询应用的数据底座就基本成型了。后续无论是做分类树浏览、添加剂详情页,还是做限量校验,都可以在这套模型上通过组合查询实现,而不必为每个功能单独造一套数据。