工单表结构设计:从业务到字段的映射
工单表是整个MES系统的核心。说白了,它就是生产任务的「身份证」。我做过好几个MES项目,每次设计工单表时,团队都会吵上半天——字段多了嫌冗余,少了又怕漏。这里我分享一套经过实战检验的设计方案。
核心字段清单
工单表至少需要包含以下几类信息:
- 工单身份:工单编号(唯一主键)、工单类型(普通/返工/试产)
- 产品信息:物料编码、物料名称、规格型号、客户料号
- 数量信息:计划数量、已生产数量、报废数量、良品数量
- 时间信息:创建时间、计划开始时间、计划结束时间、实际开始时间、实际结束时间
- 状态信息:当前状态(待生产/生产中/已完成/已关闭)、优先级
- 关联信息:销售订单号、生产批次号、工艺路线ID、版本号
重点提醒:工单编号的生成规则一定要提前定好。我见过一个项目,上线后才发现编号规则不支持跨年,结果每年1月都要改代码。建议格式:WO + 年月日 + 流水号,比如 WO202501150001。
SQL建表示例
CREATE TABLE wo_order (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
wo_no VARCHAR(32) NOT NULL UNIQUE COMMENT '工单编号',
wo_type TINYINT NOT NULL DEFAULT 0 COMMENT '工单类型 0:普通 1:返工 2:试产',
material_code VARCHAR(64) NOT NULL COMMENT '物料编码',
material_name VARCHAR(128) NOT NULL COMMENT '物料名称',
plan_qty DECIMAL(12,2) NOT NULL COMMENT '计划数量',
produced_qty DECIMAL(12,2) DEFAULT 0 COMMENT '已生产数量',
scrap_qty DECIMAL(12,2) DEFAULT 0 COMMENT '报废数量',
good_qty DECIMAL(12,2) DEFAULT 0 COMMENT '良品数量',
plan_start_time DATETIME COMMENT '计划开始时间',
plan_end_time DATETIME COMMENT '计划结束时间',
actual_start_time DATETIME COMMENT '实际开始时间',
actual_end_time DATETIME COMMENT '实际结束时间',
wo_status TINYINT NOT NULL DEFAULT 0 COMMENT '工单状态 0:待生产 1:生产中 2:已完成 3:已关闭',
priority TINYINT DEFAULT 5 COMMENT '优先级 1-10',
sale_order_no VARCHAR(64) COMMENT '销售订单号',
batch_no VARCHAR(64) COMMENT '生产批次号',
route_id BIGINT COMMENT '工艺路线ID',
version INT DEFAULT 1 COMMENT '版本号',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) COMMENT='工单主表';
嗯,这里要注意:produced_qty 和 good_qty 是冗余字段。为什么这么设计?因为每次统计都要去关联报工表做SUM,数据量大了性能扛不住。我有个项目就是一开始没加这两个字段,结果报表页面加载要十几秒,后来才补上的。
状态流转表设计:让工单「活」起来
工单不是静态的。它从创建到关闭,中间要经历很多状态变化。你想想看,如果只用一个字段记录当前状态,那历史记录怎么查?谁在什么时间改了状态?这些信息对追溯来说太重要了。
状态流转表的核心字段
- 主键ID:自增主键
- 工单ID:关联工单主表
- 源状态:变更前的状态
- 目标状态:变更后的状态
- 操作人:谁执行的变更
- 操作时间:精确到秒
- 操作备注:比如「质检不合格,退回返工」
我的习惯:状态流转表不要只记录「成功」的流转。我曾经遇到一个bug,工单状态莫名其妙跳到了「已完成」,查了半天发现是接口重复调用。从那以后,我要求所有状态变更操作,不管成功还是失败,都要记录到流转表中。失败记录可以帮我们快速定位问题。
SQL建表示例
CREATE TABLE wo_status_log (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
wo_id BIGINT NOT NULL COMMENT '工单ID',
source_status TINYINT NOT NULL COMMENT '源状态',
target_status TINYINT NOT NULL COMMENT '目标状态',
operator VARCHAR(32) NOT NULL COMMENT '操作人',
operate_time DATETIME NOT NULL COMMENT '操作时间',
remark VARCHAR(256) COMMENT '操作备注',
result TINYINT DEFAULT 1 COMMENT '操作结果 1:成功 0:失败',
error_msg VARCHAR(512) COMMENT '失败原因',
INDEX idx_wo_id (wo_id),
INDEX idx_operate_time (operate_time)
) COMMENT='工单状态流转日志表';
物料清单关联设计:工单和BOM的「联姻」
工单要生产产品,产品由物料组成。这个关联关系,就是工单和BOM(物料清单)的桥梁。我见过不少新手直接把BOM数据复制到工单里,结果BOM一更新,工单数据就全乱了。
三种关联方案对比
| 方案 | 说明 | 优点 | 缺点 |
|---|---|---|---|
| 方案一:直接引用 | 工单只存BOM的ID | 数据一致性好,BOM更新自动生效 | BOM变更会影响历史工单 |
| 方案二:快照复制 | 生成工单时复制BOM数据 | 历史工单不受BOM变更影响 | 数据冗余,BOM更新需手动同步 |
| 方案三:版本关联 | 工单关联BOM的特定版本 | 兼顾一致性和历史追溯 | 实现复杂度较高 |
我个人推荐方案三。为什么?因为制造业的BOM经常变更。比如今天工程师说「这个电阻要换型号」,如果直接引用,那之前已经生产了一半的工单怎么办?用版本关联,每个工单都「记住」自己用的是哪个版本的BOM,既灵活又可靠。
工单物料关联表设计
CREATE TABLE wo_bom_item (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
wo_id BIGINT NOT NULL COMMENT '工单ID',
bom_version VARCHAR(32) NOT NULL COMMENT 'BOM版本号',
material_code VARCHAR(64) NOT NULL COMMENT '物料编码',
material_name VARCHAR(128) NOT NULL COMMENT '物料名称',
required_qty DECIMAL(12,2) NOT NULL COMMENT '需求数量',
issued_qty DECIMAL(12,2) DEFAULT 0 COMMENT '已发料数量',
returned_qty DECIMAL(12,2) DEFAULT 0 COMMENT '已退料数量',
unit VARCHAR(8) COMMENT '单位',
is_key_material TINYINT DEFAULT 0 COMMENT '是否关键物料 0:否 1:是',
remark VARCHAR(256) COMMENT '备注',
INDEX idx_wo_id (wo_id),
INDEX idx_material_code (material_code)
) COMMENT='工单物料关联表';
避坑指南:我曾经在一个项目里,工单物料关联表没有加 bom_version 字段。结果有一次BOM更新后,所有在制工单的物料需求都变了,仓库按新BOM发料,产线按旧BOM生产,最后对不上账。那次教训让我深刻理解了「版本」的重要性。
核心逻辑流程图
下面这张图展示了工单从创建到关闭的完整数据流转路径。我习惯在设计阶段先画清楚这张图,再动手写代码。
这张图其实讲了三件事:工单主表是核心,状态流转表记录「发生了什么」,物料关联表记录「用了什么」。三者配合,才能支撑起完整的工单管理功能。
总结一下:工单表设计的关键在于「够用就好」,别贪多。状态流转表一定要记录失败操作,方便排查问题。物料关联用版本控制,别让BOM变更毁了你的在制工单。这三张表设计好了,工单模块的骨架就搭起来了。