文 / 老汪(汽车零部件财务与商业智能实战派)
专栏:【Excel BI 财务建模实战课讲义(第2阶段)】 · 期数:EP045
核心函数:Text.Combine/Table.Group/List.Transform/Text.From/List.Distinct
📌 老汪开篇导读:车间缺料碰头会上的“一对多聚合”死穴
各位财务同仁、车间成本会计、PMC 生管计划员与供应链采购BP:
在咱们汽车零部件制造企业(Tier 1 一级供应商)的每天清晨生产调度与缺料追缴碰头会上,生产厂长和采购总监往往会指着大屏幕痛斥:
“老汪,别再给我扔那种一万多行的明细流水表了!同一张工单,这里缺了螺栓占一行,那里缺了水冷板占一行,下面换个刀片又占一行!我要的是一张工单只保留一行!你能不能把这张工单底下所有缺的物料名称用顿号拼成一句话?同时把涉及的供应商全部合并告诉我,到底该找谁问责?!”
很多习惯在传统 Excel 里做报表的同学,一听到这个需求就直冒冷汗:
– 在普通 Excel 工作表中,想要实现“按工单分组、把多个子项文本合并到同一个单元格里”,通常只能退回高版本用脆弱的 TEXTJOIN 数组公式,或者逼得写一段冗长的 VBA 宏脚本去死循环拼接;
– 一旦遇上某些工单字段里混着数值型代码(如刀具规格、图号代码),公式一拉直接报 #VALUE!;
– 如果同一工单涉及的供应商有重复项(比如 3 种缺件都来自同一家晋亿实业),Excel 更是没办法顺手去重,拼出来一长串冗余文本,让高管看了直皱眉头!
今天老汪要传授给各位的,就是专门用来将列表与多行文本融会贯通为单一文本的高级工业级利器——Text.Combine!结合我们前面学过的 Table.Group,只需寥寥几行优雅的 M 代码,就能将混乱膨胀的缺料明细秒级重构为专业精简的高管决策看板!
🛠️ 第一部分:老法师拆解底层——Text.Combine 物理机理与数据契约
在动手实操前,我们必须从 M 引擎的类型系统深度吃透它的运行机制与契约规范:
Text.Combine(texts as list, optional separator as nullable text) as text
1. 核心参数与运作机理
- 第一参数
texts as list(硬性契约 · 必须是列表!):
注意看函数签名,它的入参不是普通表格(Table),也不是裸露的孤立文本(text1, text2),而是由文本元素构成的列表(List of Texts)! - 例如:
Text.Combine({"A356铝锭", "脱模剂喷嘴"}, "、")➔ 输出"A356铝锭、脱模剂喷嘴"; - 如果省略第二参数分隔符:
Text.Combine({"孙", "兴", "华"})➔ 紧密拼接输出"孙兴华"。 - 第二参数
separator as nullable text(可选分隔符):
可以指定任意自定义字符,如中文字符顿号"、"、英文逗号","、横杠"-"、甚至换行符#(lf)!
2. 🚨 老汪敲黑板:学员最高频的类型报错与“数值投毒”陷阱!
这是初学者在企业实战中最容易踩的深坑:
⚠️ 类型冲突报错:
Text.Combine具有极度严格的类型检查!如果传入的列表中混入了哪怕一个数字(Number)、日期(Date)或逻辑值(Logical),M 引擎会当场抛出:
Expression.Error: 无法将类型 Number 转换为类型 Text。
典型踩坑示例:
// 错误写法:列表里混入了数字 2026
Text.Combine({"工单", 2026, "批次"}, "-") // ❌ 立即抛错崩溃!
老法师工业级防御解法:
当列表中的元素类型不可预知时,必须先使用 List.Transform 将每个元素强转为文本形态:
// 正确姿势:先将列表元素映射转换为 Text,再安全合并!
安全文本列表 = List.Transform({"工单", 2026, "批次"}, each Text.From(_)),
安全合并 = Text.Combine(安全文本列表, "-") // ✅ 稳定输出 "工单-2026-批次"
🏭 第二部分:汽车零部件制造企业工单缺料看板实战
1. 真实业务场景画像
在某新能源底盘件与电池下壳体制造基地,ERP 系统每日导出全厂缺料停台明细台账:
– 字段包含:缺料工单号、所属车间产线、主机厂对应车型、缺件物料图号、缺件物料名称、缺料数量(件)、单件标准采购价(元)、缺料总金额(元)、建议责任供应商;
– 现状痛点:一张工单通常缺 2~3 种不同零配件(例如压铸工单同时缺铝锭与喷嘴,焊接工单同时缺副车架支架、焊丝与螺母),导致明细表长达十几行,无法一眼看出某张工单总共缺哪些物料、到底影响了哪些供应商。
2. 核心架构设计思路:Table.Group 嵌套 Text.Combine
我们利用前序所学的 Table.Group 分组聚合,在第三参数聚合列表中嵌套文本合并函数:
1. 主键分组:按 {"缺料工单号", "所属车间产线", "主机厂对应车型"} 三大维度进行主表收口;
2. 多值文本合并(Text.Combine):
– 直接从子表 _ 中提取物料名称列 _[缺件物料名称],并用顿号 "、" 串联;
3. 指标多重计算:
– 缺件品类数:通过 Table.RowCount(_) 计算品种数;
– 缺料总金额:通过 List.Sum(_[缺料总金额(元)]) 汇总缺料资金敞口;
4. 供应商去重再合并(List.Distinct + Text.Combine):
– 如果同一工单的多种缺件来自同一家供应商,先用 List.Distinct(_[建议责任供应商]) 剔除重复项,再合并输出纯净名单!
💻 第三部分:随堂课件完整 M 脚本工程实现
💡 老汪敲黑板(免改路径直接刷新秘籍):
平时做财务分析最怕换台电脑一刷新就报错“找不到文件路径”。老汪在给各位学员配套的实操课件【配置】表 A1 单元格中预置了自适应公式,大家把本课案例包解压后直接点击 Excel 的【全部刷新】即可秒级重现,绝不报红字!大家可以把这套自适应架构无缝迁移到公司的日常模型中! 实操指南点此篇文章:《实操指南》
// =========================================================================
// 专栏:【Excel BI 财务建模实战课讲义(第2阶段)】· EP045
// 模块:Text.Combine 文本列表合并与分组多值拼接(车间工单缺料合并)
// 讲师:老汪(汽车零部件财务与商业智能实战派)
// =========================================================================
let
// ---------------------------------------------------------------------
// 步骤 1:【Q001 自适应路径规范】动态定位当前工作簿同级目录
// ---------------------------------------------------------------------
当前目录 = try
let
rawPath = Text.From(Excel.CurrentWorkbook(){[Name="当前路径"]}[Content]{0}[Column1]),
cleanPath = Text.Trim(rawPath),
fixedPath = if Text.EndsWith(cleanPath, "\\") then cleanPath else cleanPath & "\\"
in
fixedPath
otherwise
"./",
// ---------------------------------------------------------------------
// 步骤 2:动态读取同级「原始业务数据表.xlsx」中 ERP 导出的缺料明细
// ---------------------------------------------------------------------
数据文件路径 = 当前目录 & "原始业务数据表.xlsx",
源文件 = Excel.Workbook(File.Contents(数据文件路径), null, true),
原始明细表 = 源文件{[Item="ERP导出_车间工单缺料明细台账", Kind="Sheet"]}[Data],
提升的标题 = Table.PromoteHeaders(原始明细表, [PromoteAllScalars=true]),
更改的数据类型 = Table.TransformColumnTypes(提升的标题, {
{"缺料工单号", type text},
{"所属车间产线", type text},
{"主机厂对应车型", type text},
{"缺件物料图号", type text},
{"缺件物料名称", type text},
{"缺料数量(件)", Int64.Type},
{"单件标准采购价(元)", type number},
{"缺料总金额(元)", type number},
{"建议责任供应商", type text}
}),
// ---------------------------------------------------------------------
// 步骤 3:核心技法 ——【Table.Group 嵌套 Text.Combine】多维度分组聚合
// 业务逻辑:
// 1. 按【工单号 + 车间产线 + 车型】进行主键归集;
// 2. 缺件物料合并清单:提取子表 [缺件物料名称] 列表,通过顿号"、"合并为单一文本;
// 3. 缺件品类数:通过 Table.RowCount(_) 计算该工单缺件品种数;
// 4. 缺料总金额:通过 List.Sum(_[缺料总金额(元)]) 汇总金额;
// 5. 责任供应商清单:提取供应商并用 List.Distinct 去重后,用 Text.Combine 拼接!
// ---------------------------------------------------------------------
分组聚合工单缺料 = Table.Group(更改的数据类型, {"缺料工单号", "所属车间产线", "主机厂对应车型"}, {
{"缺件物料合并清单(Text.Combine)", each Text.Combine(_[缺件物料名称], "、"), type text},
{"缺件品类数", each Table.RowCount(_), Int64.Type},
{"缺料总金额(元)", each List.Sum(_[缺料总金额(元)]), type number},
{"责任供应商清单(去重合并)", each Text.Combine(List.Distinct(_[建议责任供应商]), "、"), type text}
})
in
分组聚合工单缺料
📊 第四部分:清洗前后数据效果对照表
通过 Text.Combine 与 Table.Group 的强强联手,原本松散多行的车间缺料明细表,秒级收口为一人一行、信息饱满的高管追缴看板:
🚦 第五部分:老汪实战避坑指南(三大血泪经验)
1. 切勿直接向 Text.Combine 传入整张 Table 或单列数据表!
很多初学者直接写 Text.Combine(源[缺件物料名称], "、"),结果如果写成了 Text.Combine(源, "、"),M 引擎会报类型不匹配错误。记住:
– 源 是一张二维数据表(Table);
– 源[缺件物料名称] 才是从表中抽离出来的一维列表(List)!必须给它喂列表,不能直接喂表!
2. 巧用换行符 #(lf) 打造单元格多行文本
如果你希望合并出来的多个物料在 Excel 单元格里不是用顿号横向排开,而是像待办清单一样一行显示一个物料:
– M 语言原生换行符转义写法为 #(lf)(或 #(cr)#(lf));
– 写法:Text.Combine(_[缺件物料名称], "#(lf)");
– 输出到 Excel 后,只需在开始选项卡中点击【自动换行】,单元格即可优雅呈现垂直分行清单!
3. 空值 null 在列表合并中的天然免疫
在文本加号连接(如 [物料A] & [物料B])中,只要其中一个字段是 null,整个连接结果就会被“投毒”变成 null。
但 Text.Combine 拥有极强的工业级宽容度:
– 如果列表中某些元素是 null,Text.Combine 会自动将 null 视为长度为 0 的空文本跳过,绝不会因为某一行是空值而报废整个拼接链条!














暂无评论内容