夜雨聆风学习资料网

ARTICLE · 1292595

十几份 Excel BOM 散在几个人手里?用 Power Query 一次合并,还能自动标出改了什么

十几份 Excel BOM 散在几个人手里?用 Power Query 一次合并,还能自动标出改了什么

十几份 Excel BOM 散在几个人手里?用 Power Query 一次合并,还能自动标出改了什么

采购手里一份,工程手里一份,生产车间还有一份。三份表放在各自的电脑里,平时都正常,一到对账就打架:采购说按工程给的备的料,工程说上周改过用量发群里了,生产说我这份是月初拷的。

这篇要做的,是把这些散落的 BOM 收进同一个文件夹,合并成一张总表,再用一张差异表告诉你哪几行新增、哪几行用量改了、哪几行被删了。不用打开每一份文件逐个看,刷新一次就出结果。下面就用采购 / 工程 / 生产三份 BOM 做示例,文末工作簿可直接下载对照。

文末有演示工作簿,回复关键词就能领。

【第一步:把多份 BOM 合并成一张表】

前提不复杂:把要合并的 Excel 文件放进同一个文件夹,每个文件的表头列名保持一致——父项料号、子项料号、用量,至少这三列。演示工作簿里给了采购 / 工程 / 生产三份模板,每份都带一列"部门",一眼能看出这份是哪个部门的。

操作路径是:数据 → 获取数据 → 来自文件 → 从文件夹 → 填文件夹路径 → 合并并转换。

Power Query 会自动遍历文件夹里每个文件、读取内容、纵向拼成一张表。你不需要写循环,也不需要打开任何一个文件。

这里有两个细节,直接决定后面能不能追责。

第一,来源文件名要留住。从文件夹导入时,Power Query 会生成文件名这一列,把它改名成"来源文件"保留在结果表里。以后某行数据有问题,看这一列就知道它来自谁的表。如果你用模板那套,三份 BOM 本身就带"部门"列(采购 / 工程 / 生产),合并后看这一列也能直接分来源,双重保险。

但要留意一个坑:如果用"合并并转换"向导,Power Query 会自动生成一个"转换示例文件"查询,来源文件名这一列有可能在这一层被丢掉。合并完点开那个示例文件查询、回到源步骤检查一下:如果文件名列不在了,就把手动展开内容、自己控制每一步,别让向导把这条信息省掉。向导省事,但省掉的可能正好是你需要的列。

第二,一个工作簿可能有多个工作表。展开内容时选"把第一行作为表头",会得到每个文件里的所有表。如果每份 BOM 都在固定名字的表里(比如都叫"BOM"),筛一下表名;如果表名不统一,按列名特征筛,或者先把各文件的表名统一。

⚠️ 这里有一个实测最容易踩的坑:如果你把三份 BOM 拆成三个独立文件,Power Query 是按"示例文件"的表名去匹配其他文件的——只要有一个文件的表名和示例不一致,就报 Expression.Error: 该键与表中的任何行均不匹配。Item=<示例表名> Kind=Sheet,合并直接失败。解决办法很简单:把每个文件的工作表名统一成同一个(比如都叫"BOM"),保存后重跑一次就通。

合并完成后,你得到一张总表:所有文件的 BOM 行堆在一起,每行带着来源文件名。这一步解决的是"看得全",还没解决"看得出变化"。

【第二步:对比版本,先分清是哪种对比】

对比有两种口径,但用的是同一个方法,别混。

核心方法,在 Power Query 里按四步做,每一步配一段代码——把"新版表""旧版表"换成你实际的查询名就能直接用:

第一步,把两份表的用量列分别改名。在各自的查询里,把"用量"分别重命名为"新版用量"和"旧版用量",是为了后面连接展开时列名不打架。

第二步,按"父项料号 + 子项料号"把两份表做全外连接。一边有另一边没有、两边都有但用量不同,这三类情况在连接后都会保留下来:

比对 = Table.NestedJoin(新版表, {"父项料号","子项料号"}, 旧版表, {"父项料号","子项料号"}, "匹配", JoinKind.FullOuter)

第三步,展开匹配列,只带出"旧版用量"。左表本来就有"新版用量",展开后多出一列"旧版用量":

展开 = Table.ExpandTableColumn(比对, "匹配", {"旧版用量"}, {"旧版用量"})

第四步,加一列"差异类型"判断。逻辑是:旧版用量为空→新增行;新版用量为空→被删行;两边都有但用量差超过容差→用量改行;否则→无变化:

加差异 = Table.AddColumn(展开, "差异类型", each if [旧版用量] = null then "新增行" else if [新版用量] = null then "被删行" else if Number.Abs([新版用量] - [旧版用量]) > 0.0001 then "用量改行" else "无变化")

判断完,筛掉"无变化",剩下的就是差异。

跑完你可能会疑惑:被删行的"新版用量"是空的(null)、新增行的"旧版用量"也是空的(null)——这是正常现象,null 表示"这一侧的表里没有这一行",恰恰是差异判断的依据,不是出错。唯一的小遗憾是:被删行因为只存在于旧版表,它的料号会显示为空。想让被删行也把料号带出来,展开时把旧版表的父项料号、子项料号、子项名称一起带出、判断后补到空位即可(完整可运行版在文末演示工作簿里,直接下载对照)。

用到代码时有两点注意:

第一,上面代码里的"新版表""旧版表"要换成你 Power Query 里实际的查询名。比如用模板演示:新版表=工程BOM(权威版)、旧版表=采购BOM(旧备料),跑出来的就是这两份的差异;连接键"父项料号 + 子项料号"也按你表里的列名改。

第二,做"用量差"之前,确保两列都是数值类型。从别人表里拷来的用量经常是文本,文本减文本直接报错。在各自查询里先把用量列转成小数(Table.TransformColumnTypes),再进判断。注意别把料号也顺手转成数值——父项/子项料号是文本(M001、S001 带字母),设成整数会整列报 error,只有"用量"这一列需要转。

同一个方法,两种用法:

▪ 用法一,验证同一版本的两份拷贝是否一致。场景是工程发给采购和生产的是同一版,你想确认没人私下改过。跑出来理论上应该是空的——如果不空,说明两份表已经不一致了,这本身就是问题。

▪ 用法二,旧版对新版,找出三类变更。这是更常用的场景。两份表本来就是不同版本,所以结果里出现"新增""被删""用量改"都是正常的,不需要追求空表。

两个边界提醒:

第一,如果同一父项下同一子项允许重复出现(不同位置、不同版本各一行),连接键会重复,全外连接会变成多对多,结果串行。遇到这种情况,把版本号或行号也放进连接键里,别只用"父项 + 子项"。

第二,用量比较用"差值大于一个很小的容差(比如 0.0001)",不要直接写"不相等"。Excel 里的浮点数和文本型数字,会让"看起来一样"的两个数判成不同,加一个容差能挡掉大量假差异。

【跑之前,自检三处】

第一,文件夹里别混无关文件。以 ~$ 开头的临时文件、说明文档、其他报表混进去,会被一起合并,结果表里多出一堆脏行。合并前清一遍文件夹,或者按扩展名和文件名规则先筛。

第二,列名必须统一。一份写"父项料号",一份写"父件",Power Query 合并时会当成两列,结果是错位而不是报错。合并前统一列名,或者在 Power Query 里先重命名再合并。模板那三份 BOM 列名已经统一,照着改你自己的表就行。

第三,格式先归一。.xls 和 .xlsx 混放能读,但慢,建议统一另存为 .xlsx;表头不在第一行、存在合并单元格,读取会错位——这两条比编码问题更常见,也更容易被忽略。

【下一篇】

合并和对比跑通之后,你手里就有三样东西了:物料字典、结构表、多版本差异表。下一篇,我把它们串成一张「动态 BOM 总表」——物料字典做唯一来源,结构表做关系,差异表做变更记录,拼成一张刷新即更新的总表。关注,下篇见。

【领取演示工作簿】

正文里那三段是核心代码,够你跑起来用了。如果你想要完整可运行版 + 采购 / 工程 / 生产三份示例 BOM + 跑出来的差异结果示例(方便直接下载保存、对照格式),后台回复【BOM对比】领取。

和前三篇一样,回复就发,不用转发。先把文件夹清干净,再点刷新。

封面图由 AI 辅助生成,正文内容为本人整理创作。


晓夜子工业表 | 专注制造业 BOM、物料与库存报表 做好工业表,少做重复活

回首页,搜索你想要的文档

在首页搜索框输入关键词,快速定位资料

文库首页搜索指引 立即搜索

相关学习资料