简介:这份ERP数据库文档面向企业信息化学习者、软件工程与信息管理专业学生,以及需要梳理ERP数据模型的开发者,帮助理解制造企业核心业务表结构与字段设计。内容覆盖销售预测单、销售订单、主生产计划与物料需求计划的主从表、物料清单、工作中心信息表、工艺路线表、能力需求计划报表,以及入库单、出库单、库存盘点单、采购申请单、采购订单、车间任务单、加工单等单据,并给出销售、MPS、MRP、CRP、采购、生产、库存与数据维护等菜单模块划分,便于对照字段含义与业务流程。资源包共1个doc文件,约30KB,以文档形式集中呈现各表字段清单,适合作为数据库设计参考或课程实验建模依据。目前已有482人学习下载,可帮助读者快速搭建ERP数据字典、核对表间关系并完善系统设计。
1. 一份 ERP 数据库文档,为什么值得你花时间拆开看
很多做 ERP 实施或者二次开发的朋友,拿到一份数据库设计文档时,第一反应往往是「字段太多,先放着」。但真正做过项目的人都知道,ERP 系统的核心逻辑几乎全藏在表结构和字段关系里。这份[详细完整版]ERP数据库.doc覆盖了从销售预测、主生产计划(MPS)、物料需求计划(MRP)、能力需求计划(CRP),到采购、生产、库存的完整数据链路,基本上把制造业 ERP 的主干流程都串起来了。它适合正在做 ERP 选型评估的实施顾问、需要理解数据库结构的二次开发工程师,以及准备 ERP 实施工程师面试的求职者。你可以把它当成一份数据字典来查字段,也可以当成一份业务蓝图来理解模块之间的数据流转关系。下面我会按「先看懂结构、再动手建表、最后避坑」的顺序,把这份文档拆成可复现的操作笔记。
2. 从销售预测到 MRP 报表:核心表结构与字段设计逻辑
2.1 销售与预测模块的表结构拆解
销售预测单和销售订单是整个 ERP 系统的数据源头。预测单的字段包括物料编码、物料名称、起始日期、结束日期、预测数量、均化类型。其中「均化类型」这个字段值得单独说——它决定了预测数量如何分摊到各个时段,常见做法是按月均化、按周均化或者自定义权重分配。销售订单则多了规格型号、计量单位、完工日期、交货日期、客户名称、业务员这些字段,这些字段在后续的 MPS 运算中会作为「订单量」的来源。
我一般会先把这两张表的字段关系理清楚,因为后面 MPS 和 MRP 的毛需求量计算,本质上就是预测量加订单量再减去库存和已分配量。如果你连预测单的均化逻辑都没搞明白,后面 MRP 跑出来的净需求一定是乱的。
-- 销售预测单建表语句(以 MySQL 为例) CREATE TABLE sales_forecast ( id INT PRIMARY KEY AUTO_INCREMENT, material_code VARCHAR(32) NOT NULL COMMENT '物料编码', material_name VARCHAR(128) NOT NULL COMMENT '物料名称', start_date DATE NOT NULL COMMENT '起始日期', end_date DATE NOT NULL COMMENT '结束日期', forecast_qty DECIMAL(12,2) DEFAULT 0 COMMENT '预测数量', smoothing_type VARCHAR(16) COMMENT '均化类型:MONTH/WEEK/CUSTOM', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_material (material_code), INDEX idx_date_range (start_date, end_date) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;这段建表语句里,smoothing_type用枚举值来区分均化方式,比直接存中文更利于后续程序判断。idx_date_range这个联合索引是为了加速按日期范围查询预测数据的场景,MRP 运算时经常需要按时间段筛选,没有这个索引数据量一大就会明显变慢。
2.2 MPS 与 MRP 报表的主从表设计
主生产计划报表和物料需求计划报表采用的是主从表结构。主表存的是物料层面的计划参数,包括物料编码、物料名称、安全库存量、前期库存量、批量规则、批量、计划展望期、需求时界、计划时界、提前期、合格率、计划员编码、计划编制日期。从表存的是时段层面的明细数据,包括时区、时段、日期、预测量、订单量、毛需求量、计划接受量、可用库存量、净需求量、计划产出量、计划投入量、可供销售量。
这里有几个参数直接决定 MRP 运算结果是否正确。需求时界和计划时界是两个容易被忽略但极其关键的字段。需求时界之内,系统一般不允许自动修改已确认的计划订单;计划时界之内,系统可以自动调整但会给出提示;只有超出计划时界的部分才允许完全由系统自动生成。如果你在实施时把这两个值设成一样的,MRP 运算就会失去灵活性,要么全部锁死要么全部放开,实际业务中根本没法用。
批量规则和批量决定了净需求如何转化为计划产出量。常见做法有直接批量、固定批量、经济订货批量等。直接批量就是净需求多少就产出多少,固定批量则是按设定的批量倍数向上取整。我见过不少项目因为批量规则设错,导致计划产出量要么严重偏大造成库存积压,要么偏小导致频繁缺料。
-- MPS/MRP 主表(两张表结构一致,用 plan_type 区分) CREATE TABLE mrp_main ( id INT PRIMARY KEY AUTO_INCREMENT, plan_type VARCHAR(8) NOT NULL COMMENT 'MPS 或 MRP', material_code VARCHAR(32) NOT NULL, material_name VARCHAR(128), safety_stock DECIMAL(12,2) DEFAULT 0 COMMENT '安全库存量', initial_stock DECIMAL(12,2) DEFAULT 0 COMMENT '前期库存量', lot_rule VARCHAR(16) COMMENT '批量规则:DIRECT/FIXED/EOQ', lot_size DECIMAL(12,2) COMMENT '批量', planning_horizon INT COMMENT '计划展望期(天)', demand_fence INT COMMENT '需求时界(天)', planning_fence INT COMMENT '计划时界(天)', lead_time INT COMMENT '提前期(天)', yield_rate DECIMAL(5,2) DEFAULT 100 COMMENT '合格率(%)', planner_code VARCHAR(16) COMMENT '计划员编码', plan_date DATE COMMENT '计划编制日期', UNIQUE KEY uk_material_plan (material_code, plan_type) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- MPS/MRP 从表(时段明细) CREATE TABLE mrp_detail ( id INT PRIMARY KEY AUTO_INCREMENT, main_id INT NOT NULL COMMENT '关联主表 id', time_zone VARCHAR(16) COMMENT '时区', period VARCHAR(16) COMMENT '时段', period_date DATE COMMENT '日期', forecast_qty DECIMAL(12,2) DEFAULT 0 COMMENT '预测量', order_qty DECIMAL(12,2) DEFAULT 0 COMMENT '订单量', gross_requirement DECIMAL(12,2) DEFAULT 0 COMMENT '毛需求量', scheduled_receipt DECIMAL(12,2) DEFAULT 0 COMMENT '计划接受量', available_stock DECIMAL(12,2) DEFAULT 0 COMMENT '可用库存量', net_requirement DECIMAL(12,2) DEFAULT 0 COMMENT '净需求量', planned_output DECIMAL(12,2) DEFAULT 0 COMMENT '计划产出量', planned_input DECIMAL(12,2) DEFAULT 0 COMMENT '计划投入量', available_to_promise DECIMAL(12,2) DEFAULT 0 COMMENT '可供销售量', FOREIGN KEY (main_id) REFERENCES mrp_main(id) ON DELETE CASCADE, INDEX idx_main_date (main_id, period_date) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;从表通过main_id外键关联主表,ON DELETE CASCADE保证删除主表记录时明细自动清理。idx_main_date这个联合索引在按物料和时间段查询报表时非常关键,MRP 报表查询功能基本都靠它来加速。
2.3 物料清单与工艺路线的数据结构
物料清单(BOM)的字段包括层次号、母件物料编码、物料编码、物料名称、规格型号、计量单位、数量、合格率、提前期、物料来源。层次号决定了 BOM 的层级关系,母件物料编码指向上一级物料。物料来源用来区分是自制、外购还是委外,这个字段直接影响 MRP 运算时是生成车间任务单还是采购申请单。
工艺路线表的字段是物料号、工序号、工序名称、工作中心名称、加工时间单位、加工时间。工作中心信息表则包含工作中心代码、工作中心名称、车间代码、班次、每班小时数、每班平均人数、设备数。这三张表串起来,才能算出 CRP 能力需求计划报表里的负荷量和加工能力。
-- 物料清单表 CREATE TABLE bom ( id INT PRIMARY KEY AUTO_INCREMENT, level_no INT NOT NULL COMMENT '层次号', parent_code VARCHAR(32) COMMENT '母件物料编码', material_code VARCHAR(32) NOT NULL COMMENT '物料编码', material_name VARCHAR(128), spec_model VARCHAR(128) COMMENT '规格型号', unit VARCHAR(16) COMMENT '计量单位', qty DECIMAL(12,4) NOT NULL COMMENT '数量', yield_rate DECIMAL(5,2) DEFAULT 100 COMMENT '合格率', lead_time INT COMMENT '提前期', source_type VARCHAR(16) COMMENT '物料来源:MAKE/BUY/OUTSOURCE', INDEX idx_parent (parent_code), INDEX idx_material (material_code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;qty字段用DECIMAL(12,4)而不是整数,是因为 BOM 中可能存在小数用量,比如某些化工或电子行业物料按克或按米计算。source_type用英文枚举值,方便程序判断分支逻辑。
3. 库存、采购与生产模块的表关系与建表实操
3.1 出入库与盘点表的字段设计
入库单分三种类型:产品入库、原材料入库、在制品入库。字段包括入库单号、入库日期、入库类型、入库仓库代码、仓库名称、物料编码、物料名称、规格类型、计量单位、数量、单价、金额。出库单同样分三种类型:产品销售、原材料领料、在制品领料,字段结构与入库单基本对称。
库存盘点单的字段值得注意,它同时记录了账面数量、账面金额、实际数量、实际金额、盈亏数量、盈亏金额、盘点数量、盘点日期。这种设计的好处是盘点差异一目了然,不需要事后另外算。盈亏数量等于实际数量减账面数量,盈亏金额等于实际金额减账面金额,这两个字段虽然可以由程序计算,但直接存下来在查询报表时省去了实时计算的开销。
-- 入库单 CREATE TABLE inbound_order ( id INT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL UNIQUE COMMENT '入库单号', inbound_date DATE NOT NULL COMMENT '入库日期', inbound_type VARCHAR(16) NOT NULL COMMENT '入库类型:PRODUCT/MATERIAL/WIP', warehouse_code VARCHAR(16) NOT NULL COMMENT '仓库代码', warehouse_name VARCHAR(64), material_code VARCHAR(32) NOT NULL, material_name VARCHAR(128), spec_type VARCHAR(128) COMMENT '规格类型', unit VARCHAR(16), qty DECIMAL(12,2) NOT NULL DEFAULT 0, unit_price DECIMAL(12,4) DEFAULT 0, amount DECIMAL(14,2) DEFAULT 0, INDEX idx_warehouse (warehouse_code), INDEX idx_material (material_code), INDEX idx_date (inbound_date) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;order_no加了唯一约束,防止重复录入。三个索引分别覆盖按仓库查、按物料查、按日期查这三种最常见的报表需求。金额字段用DECIMAL(14,2)是因为汇总金额可能比较大,整数部分留了 12 位。
3.2 采购申请单与采购订单的流转关系
采购申请单的字段包括物料编码、物料名称、规格型号、计量单位、数量、单价、金额、需求日期、申请部门、业务员、申请日期。采购订单在此基础上多了计划到货日期、实际到货日期、订购日期、客户名称。从字段差异可以看出,采购申请单是内部需求凭证,采购订单是对外执行凭证。
实际项目中,MRP 运算产生的计划产出量中,物料来源为「外购」的部分会自动生成采购申请单。采购部门审核后转为采购订单。这个流转过程在数据库层面通常通过一个状态字段来控制,但这份文档里没有明确列出状态字段,常见做法是在采购申请单上加一个status字段来标记「待审核 / 已转单 / 已关闭」。
-- 采购申请单 CREATE TABLE purchase_request ( id INT PRIMARY KEY AUTO_INCREMENT, material_code VARCHAR(32) NOT NULL, material_name VARCHAR(128), spec_model VARCHAR(128), unit VARCHAR(16), qty DECIMAL(12,2) NOT NULL, unit_price DECIMAL(12,4) DEFAULT 0, amount DECIMAL(14,2) DEFAULT 0, demand_date DATE COMMENT '需求日期', apply_dept VARCHAR(64) COMMENT '申请部门', operator VARCHAR(32) COMMENT '业务员', apply_date DATE COMMENT '申请日期', status VARCHAR(16) DEFAULT 'PENDING' COMMENT 'PENDING/TRANSFERRED/CLOSED', INDEX idx_material (material_code), INDEX idx_status (status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;status字段的默认值设为PENDING,采购申请单创建后处于待审核状态。idx_status索引让「查询所有待审核申请单」这类操作走索引而不是全表扫描。
3.3 车间任务单与派工单的关联
车间任务单的字段是任务编码、物料编码、物料名称、计划开工日期、计划完工日期、车间代码。加工单或派工单的字段是物料编码、物料名称、工序号、工作中心代码、计划开工日期、计划完工日期、优先级、实际完工日期。
车间任务单是面向整批任务的,派工单是面向具体工序和工作中心的。一个车间任务单可以拆成多个派工单,每个派工单对应工艺路线中的一道工序。优先级字段用来决定同一工作中心上多个派工单的加工顺序,常见做法是用数字表示,数字越小优先级越高。
-- 派工单 CREATE TABLE dispatch_order ( id INT PRIMARY KEY AUTO_INCREMENT, material_code VARCHAR(32) NOT NULL, material_name VARCHAR(128), process_no INT NOT NULL COMMENT '工序号', work_center_code VARCHAR(16) NOT NULL COMMENT '工作中心代码', plan_start_date DATE COMMENT '计划开工日期', plan_end_date DATE COMMENT '计划完工日期', priority INT DEFAULT 5 COMMENT '优先级,数字越小越优先', actual_end_date DATE COMMENT '实际完工日期', INDEX idx_work_center (work_center_code), INDEX idx_priority (priority), INDEX idx_plan_date (plan_start_date) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;idx_work_center和idx_priority这两个索引在 CRP 能力需求计划运算时非常重要。CRP 需要按工作中心汇总负荷量,然后和该工作中心的加工能力做对比。如果没有这两个索引,每次排产都要全表扫描派工单表,数据量上万条之后响应时间会明显变长。
4. 菜单结构与模块划分:从功能入口反推数据流
4.1 销售与计划模块的菜单逻辑
菜单结构是:销售管理(市场预测单、销售订单)、MPS 管理(MPS 基本信息表、MPS 报表生成、MPS 报表查询)、MRP 管理(MRP 基本信息表、MRP 报表生成、MRP 报表查询)、CRP 管理(CRP 报表生成、CRP 报表查询)。
这个菜单划分反映了一个典型的数据流:销售预测和订单是输入,MPS 是主计划层,MRP 是物料层,CRP 是能力层。MPS 基本信息表对应的是主表参数维护,MPS 报表生成触发运算逻辑,MPS 报表查询展示从表明细。MRP 的菜单结构完全对称,说明两者的运算框架是一致的,区别只在于 MPS 针对的是独立需求物料,MRP 针对的是相关需求物料。
4.2 采购、生产与库存模块的菜单关系
采购管理菜单包括生成请购单、采购订单管理、采购到货管理。生产管理菜单包括生成车间任务书、生成加工单、生成派工单、生产完工管理。库存管理菜单包括入库管理、出库管理、库存盘点。数据维护菜单包括物料清单表、工作中心信息表、工艺路线表。
从菜单顺序可以看出系统的操作流程:先维护基础数据(物料清单、工作中心、工艺路线),再跑计划(MPS、MRP、CRP),然后根据计划结果生成采购申请和生产任务,最后通过出入库和盘点来闭环库存。这个流程和标准的制造业 ERP 逻辑是一致的。
-- 能力需求计划报表(CRP) CREATE TABLE crp_report ( id INT PRIMARY KEY AUTO_INCREMENT, work_center_code VARCHAR(16) NOT NULL COMMENT '工作中心代码', period VARCHAR(16) COMMENT '时段', period_date DATE COMMENT '日期', load_qty DECIMAL(12,2) DEFAULT 0 COMMENT '负荷量(小时)', capacity DECIMAL(12,2) DEFAULT 0 COMMENT '加工能力(小时)', load_diff DECIMAL(12,2) DEFAULT 0 COMMENT '能力负荷差', cumulative_diff DECIMAL(12,2) DEFAULT 0 COMMENT '累计能力负荷差', INDEX idx_wc_date (work_center_code, period_date) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;load_diff等于负荷量减加工能力,正数表示能力不足,负数表示能力富余。cumulative_diff是累计值,用来观察一段时间内的整体能力平衡情况。idx_wc_date联合索引覆盖了按工作中心和日期查询的典型场景。
5. 避坑与排查:建表和跑 MRP 时最容易翻车的五个地方
5.1 需求时界和计划时界设成相同值
现象:MRP 运算后,要么所有计划订单都被锁死无法调整,要么系统随意修改已确认的订单,计划员完全失控。
原因:需求时界和计划时界设置相同,导致系统没有缓冲区间。正常做法是需求时界小于计划时界,两者之间留出一段「可调整但需提示」的区间。
解决:需求时界一般设为提前期的一半左右,计划时界设为提前期加一个安全周期。具体数值要根据物料采购周期和业务响应速度来定,没有万能公式。
5.2 批量规则选错导致库存积压或频繁缺料
现象:MRP 跑出来的计划产出量远大于实际净需求,仓库里堆了一堆用不完的料;或者计划产出量太小,生产线上三天两头缺料停线。
原因:批量规则选了固定批量但批量值设得太大,或者选了直接批量但供应商有最小起订量要求。
解决:先确认物料的采购或生产约束。供应商有 MOQ 的用固定批量,自制件按经济批量或直接批量。批量值要结合历史消耗数据来定,不要拍脑袋。
5.3 BOM 层次号维护错误导致 MRP 展开层级混乱
现象:MRP 运算时某些物料的毛需求量算多了或算少了,BOM 展开后层级关系对不上。
原因:层次号没有按父子关系正确维护,或者同一个物料在不同父件下的层次号不一致。
解决:BOM 维护时严格按层级递增,母件层次号必须小于子件层次号。建议在程序里加校验,保存时检查层次号是否满足父子约束。
5.4 工作中心能力数据不准确导致 CRP 报表失真
现象:CRP 报表显示某个工作中心负荷率长期超过 150%,但实际车间并没有那么忙。
原因:工作中心信息表里的每班小时数、每班平均人数、设备数没有及时更新,或者工艺路线里的加工时间单位不统一。
解决:定期核对工作中心的基础数据,加工时间单位统一为小时或分钟,不要混用。工艺路线变更后同步更新 CRP 参数。
5.5 出入库单的金额字段精度不够导致对账差异
现象:库存金额和财务账对不上,差异不大但一直存在。
原因:单价字段用了FLOAT或DECIMAL精度不够,大量记录累加后产生舍入误差。
解决:单价用DECIMAL(12,4),金额用DECIMAL(14,2),所有计算在数据库层面用DECIMAL类型完成,不要在程序里用浮点数中转。
注意:以上五个坑里,需求时界和批量规则的问题在项目上线初期最容易暴露,建议在 UAT 阶段就重点验证这两项。
6. 进阶用法:用 SQL 验证 MRP 运算结果是否合理
建完表之后,怎么验证 MRP 跑出来的数据是对的?我一般会用几条 SQL 做交叉校验。第一条是检查净需求量是否等于毛需求量减计划接受量减可用库存量加安全库存量。如果不等,说明运算逻辑或者数据有问题。
-- 校验净需求量计算是否正确 SELECT d.id, d.material_code, d.gross_requirement, d.scheduled_receipt, d.available_stock, m.safety_stock, d.net_requirement, (d.gross_requirement - d.scheduled_receipt - d.available_stock + m.safety_stock) AS expected_net FROM mrp_detail d JOIN mrp_main m ON d.main_id = m.id WHERE ABS(d.net_requirement - (d.gross_requirement - d.scheduled_receipt - d.available_stock + m.safety_stock)) > 0.01;这条 SQL 会找出所有净需求量计算异常的记录。ABS(...) > 0.01是为了容忍浮点误差,虽然我们用了DECIMAL,但保险起见还是留一点余量。如果查出来有记录,就要回去检查 MRP 运算程序的逻辑。
第二条是检查计划产出量是否满足批量规则约束。如果批量规则是固定批量,计划产出量应该是批量的整数倍。
-- 校验固定批量规则下计划产出量是否为批量的整数倍 SELECT d.id, d.material_code, d.planned_output, m.lot_size, d.planned_output % m.lot_size AS remainder FROM mrp_detail d JOIN mrp_main m ON d.main_id = m.id WHERE m.lot_rule = 'FIXED' AND m.lot_size > 0 AND d.planned_output % m.lot_size != 0;%取模运算在 MySQL 里可以直接用。如果remainder不为零,说明计划产出量没有按固定批量取整,需要检查运算程序。
第三条是检查累计能力负荷差是否单调变化。正常情况下,累计能力负荷差应该是逐时段累加的,不应该出现跳跃。
-- 检查 CRP 累计能力负荷差是否连续 SELECT c1.work_center_code, c1.period_date, c1.cumulative_diff, c2.period_date AS prev_date, c2.cumulative_diff AS prev_diff, (c1.cumulative_diff - c2.cumulative_diff) AS diff_change FROM crp_report c1 JOIN crp_report c2 ON c1.work_center_code = c2.work_center_code AND c2.period_date = ( SELECT MAX(period_date) FROM crp_report WHERE work_center_code = c1.work_center_code AND period_date < c1.period_date ) WHERE ABS((c1.cumulative_diff - c2.cumulative_diff) - c1.load_diff) > 0.01;这条 SQL 的逻辑是:当前时段的累计能力负荷差减去上一时段的累计能力负荷差,应该等于当前时段的能力负荷差。如果不等,说明累计值算错了。
这三条校验 SQL 我每次跑完 MRP 都会执行一遍,花不了几分钟,但能提前发现大部分数据问题。从那以后我每次部署完 MRP 运算模块,都强制走一遍这三条校验,再也没出现过计划数据对不上的情况。希望帮到你。
本文还有配套的精品资源,点击获取