专栏定位:系统拆解 Power Query M 语言底层核心逻辑,紧密围绕汽车零部件制造企业(Tier 1)财务管控、工时核算、工装模具与生产条码真实业务场景,输出工业级实操讲义与自动化解决方案。
文 / 老汪(汽车零部件财务与商业智能实战派)
大家好,我是老汪。
在咱们汽车零部件制造企业(Tier 1 一级供应商)月末进行工时稽核与生产成本核算的时候,成本会计与工时核算员最常抱怨的一个痛点就是:车间现场传上来的台账,总喜欢把多个技工或者多道工序挤在同一个单元格里!
典型的场景就像下面这样:
在压铸车间或冲压车间,一套重达几吨的大型精密工装模具(比如 3500T 压铸岛前舱模具、车身侧围大型冲压模具)进行换模、对模或热态调模时,往往需要 3~5 名资深机修钳工和调模技工协同配合数个小时。车间班长在填报《换模保全工单》时,为了图省事,在“参与作业技工”这一列直接输入:张伟、李强、王建国、刘波,甚至换了另一个车间,又变成了英文逗号 赵敏,刘海,陈刚,或者是分号 周鹏;吴勇。
月末成本会计在做计件工时分摊与绩效核算时,面临两个硬骨头:
1. 人数难统计:这个工单到底有几个人参与?如果用传统 Excel 公式,得写复杂的 =LEN(A2)-LEN(SUBSTITUTE(A2,"、",""))+1,一旦工人随手在末尾多打了一个顿号,人数直接算错,工时差之千里;
2. 明细无法直接入账:财务 ERP 系统要求一人一行一工时,把 4 个人挤在一个格子里,根本没办法匹配人事工号与车间工资结算系统!
今天这节课,老汪就带大家深入吃透 Power Query 文本拆分双剑客——Text.Split(指定分隔符拆分)、Text.SplitAny(多符号兼容拆分),以及字符流拆分利器 Text.ToList(原子级单字符拆解)。学完这一讲,无论车间怎么胡乱混用分隔符,你都能在内存中瞬间将其化为结构化列表,不仅秒算人数、自动平摊人均工时,更能一键展开为标准明细表!
一、 老汪白话底层逻辑:文本拆分的本质是“降维入列”
在 Power Query 的底层架构中,文本(Text)是一个整体的标量标号。但当我们想要对文本内部的各组成要素进行统计、计数或独立核算时,必须将其解构为列表(List)。
┌─────────────────────────────────────────────────────────────┐
│ 原始合并单元格文本: "张伟、李强、王建国、刘波" │
└──────────────────────────────┬──────────────────────────────┘
│ Text.Split(..., "、")
▼
┌─────────────────────────────────────────────────────────────┐
│ 内存解构结果 (List 列表): {"张伟", "李强", "王建国", "刘波"} │
└──────────────────────────────┬──────────────────────────────┘
├─► ① List.Count ➔ 统计参与人数 (4人)
├─► ② 工时平摊 ➔ 6.0小时 / 4 = 1.5小时/人
└─► ③ 展开为新行 ➔ 生成 4 行标准工时核算明细
1. 核心函数语法透视
① Text.Split:标准单分隔符切片
Text.Split(text as nullable text, separator as text) as list
- 核心逻辑:以
separator为刀,将文本逐段切开,返回由切片字符串构成的列表; - 缺省容错:如果文本中根本没有出现
separator,它不会报错,而是返回只包含该原始文本单个元素的列表(例如"武松"拆分后得到{"武松"},List.Count结果就是 1,完全符合业务逻辑)。
② Text.SplitAny:多字符多符号容错切片(老汪强推)
Text.SplitAny(text as nullable text, separators as text) as list
- 工业级实战价值:车间人员填表极不规范,有的打中文顿号
、,有的敲英文逗号,,有的敲中文逗号,或分号;。Text.SplitAny允许你在第二个参数中传入所有可能出现的分隔符集合(例如"、,;,;"),只要遇到其中任意一个字符,就立即切分!
③ Text.ToList:原子级单字符流拆解
Text.ToList(text as nullable text) as list
- 核心机制:不需要任何分隔符,直接将整个字符串的每一个字符(中文字、英文字母、数字、符号)拆解成独立的单字符列表;
- 典型应用:常用于汽车零部件 17 位 VIN 码、MES 扫码枪导出的纯连续流水号(如
819204859102)的逐位重构与格式化。
二、 业务实战案一:压铸与冲压车间工装换模工时智能平摊
1. 原始业务痛点台账
某汽车零部件工厂有压铸、冲压、数控机加等车间,各工段在维护《车间工装换模工单记录》时,技工名单由班组长手工填报,存在严重的挤占单元格现象:
| 换模工单号 | 所属车间工段 | 工装模具编号 | 换模总工时(小时) | 参与作业技工(名单合并) | 换模复杂度 |
|---|---|---|---|---|---|
| WO-202611-001 | 压铸一车间-DC3500T | MOLD-DC-3500-01 | 6.0 | 张伟、李强、王建国、刘波 | A级特级复杂 |
| WO-202611-002 | 压铸二车间-DC2000T | MOLD-DC-2000-03 | 4.5 | 赵敏,刘海,陈刚 | B级常规换模 |
| WO-202611-003 | 精密冲压车间-ST800T | MOLD-ST-800-02 | 3.0 | 周鹏;吴勇 | B级常规换模 |
| WO-202611-005 | 数控机加车间-CNC01 | FIX-CNC-DISC-01 | 2.0 | 武松 | C级快速调模 |
2. 清洗目标与关键步骤
- 多符号兼容拆分:将字段中的顿号、逗号、分号统一拆开为纯技工姓名列表;
- 作业总人数统计:调用
List.Count获取每一张工单的出勤人数; - 人均工时平摊计算:
[人均分配工时] = Number.Round([换模总工时] / [作业总人数], 2); - 一键展开为标准明细行:调用
Table.ExpandListColumn,将原本挤在一起的单行数据扩展为每个人独占一行的标准台账。
三、 业务实战案二:新能源电驱总成出厂流水条码重构
1. 业务场景背景
在新能源汽车三电(电池、电机、电控)总成包装下线时,车间扫码枪导出的纯数字/字母流水号是无间隔的连续字符串(如 819204859102)。但主机厂(如比亚迪、特斯拉、蔚来等)的质量追溯系统(EDI 接口)严格要求必须转换为统一的 3-4-5 分组格式:819-2048-59102。
2. 解题利器:Text.ToList 字符流重塑
如果用传统的字符串截取(Text.Middle、Text.Start),需要写三段嵌套公式。而在 M 语言中,我们可以用极富函数式编程美感的方式处理:
1. Text.ToList([原始条码]) ➔ 得到 12 个独立字符组成的列表 {"8", "1", "9", "2", ...};
2. List.Range 切片 ➔ 分别提取前 3 位、中间 4 位、后 5 位字符;
3. Text.Combine 重新串联 ➔ 分段拼接并插入连字符 -,一步到位输出标准规范码!
四、 工业级 M 语言核心脚本(自适应动态路径版)
以下为老汪为大家编写的标准 M 语言工程代码,已全面遵循 Q001 动态相对路径标准,解压后可直接在任意电脑上刷新演练:
// ====================================================================
// 查询 1:【换模工时分摊明细表】(Text.SplitAny + List.Count + ExpandList)
// ====================================================================
let
// 1. 动态自适应提取当前工作簿路径
当前目录 = 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",
源 = Excel.Workbook(File.Contents(数据源路径), null, true),
目标Sheet = 源{[Item="车间工装换模工单记录", Kind="Sheet"]}[Data],
提升标题 = Table.PromoteHeaders(目标Sheet, [PromoteAllScalars=true]),
更改类型 = Table.TransformColumnTypes(提升标题,{
{"换模工单号", type text},
{"所属车间工段", type text},
{"工装模具编号", type text},
{"模具类型", type text},
{"换模总工时_小时", type number},
{"参与作业技工_挤占单元格", type text},
{"换模复杂度等级", type text}
}),
// 3. 核心步骤 A:使用 Text.SplitAny 兼容多种中英文分隔符(顿号、逗号、分号)
添加技工列表列 = Table.AddColumn(更改类型, "技工列表", each
let
原始文本 = Text.From([#"参与作业技工_挤占单元格"]),
拆分列表 = Text.SplitAny(原始文本, "、,;,;"),
// 清理可能产生的空格或空文本
清洗后列表 = List.Select(List.Transform(拆分列表, Text.Trim), each _ <> "")
in
清洗后列表,
type list
),
// 4. 核心步骤 B:使用 List.Count 快速计算实际出勤技工总人数
添加作业人数列 = Table.AddColumn(添加技工列表列, "作业总人数", each List.Count([技工列表]), Int64.Type),
// 5. 核心步骤 C:人均分配工时 = 工单总工时 / 作业总人数(保留2位小数)
添加人均工时列 = Table.AddColumn(添加作业人数列, "人均分配工时_小时", each
Number.Round([#"换模总工时_小时"] / [作业总人数], 2),
type number
),
// 6. 核心步骤 D:展开列表到新行(ExpandListColumn),实现一人一行
展开技工明细 = Table.ExpandListColumn(添加人均工时列, "技工列表"),
重命名列 = Table.RenameColumns(展开技工明细, {{"技工列表", "换模技工姓名"}}),
// 7. 规整字段呈现顺序
重排列 = Table.SelectColumns(重命名列, {
"换模工单号", "所属车间工段", "工装模具编号", "换模总工时_小时",
"换模技工姓名", "作业总人数", "人均分配工时_小时", "换模复杂度等级"
})
in
重排列
五、 老汪敲黑板:文本拆分三大实战避坑要诀
在实际的工厂生产与财务核算系统对接中,文本拆分往往看似简单,却极易在异常数据上“翻车”。老汪给大家总结了以下三条金科玉律:
1. 警惕末尾悬空分隔符(“虚增人头”陷阱)
有些车间师傅录单时习惯在最后一个名字后也顺手打一个顿号,例如输入:张三、李四、。
如果直接执行 Text.Split("张三、李四、", "、"),M 引擎会非常老实地返回一个包含 3 个元素的列表:{"张三", "李四", ""}!
结果后续一算 List.Count,人数变成了 3 个人!原本 4 小时的工时除以 3,导致人均工时缩水,引起工人巨大争议。
老汪锦囊:在
Text.Split或Text.SplitAny之后,务必套一层List.Select(..., each _ <> ""),将切片出来的空字符串剔除干净,从根源上防御“幽灵工时”!
2. 数字字段必须显式转文本(Text.From 保护伞)
如果在执行 Text.Split 或 Text.ToList 时,传入的字段是纯数值格式(例如整数格式的扫码枪流水号 819204859102),M 引擎会直接抛出类型不匹配异常(Expression.Error: 无法将 Number 转换为 Text)。
老汪锦囊:在处理文本拆分前,永远使用
Text.From(...)给原始字段穿一层防护衣,确保进入切片管道的数据 100% 为文本类型。
3. 表格拆分到列(UI操作)vs 内存拆分(M代码)的选择
很多初学者喜欢在 Power Query 界面上点击【拆分列】➔【按分隔符】,系统会自动生成很多新列(姓名.1、姓名.2、姓名.3…)。
这种方法在财务建模中存在严重隐患:如果某张工单突然来了 6 个人,系统只拆了前 4 列,多出的人就会被悄无声息地吞掉!
老汪建议:涉及多值统计与人均分摊时,坚决采用本文介绍的
Text.Split➔ 内存列表 ➔Table.ExpandListColumn纵向展开为多行 的模式,不管来几个人,系统自动纵向延伸,永不丢数据!
六、 老汪结语与随堂课件下载
工欲善其事,必先利其器。Power Query 的真正魅力从来不是去代替手工筛选,而是将车间最无序、最不规范的“野路子填报”,在财务端一键重塑为严谨规范的工业级明细台账。
大家在阅读完讲义后,请务必下载文末的随堂课件包。课件中已经为大家配置好了《原始业务数据表.xlsx》和预置自适应公式的《最终完成版_带PQ查询.xlsx》,解压即可直接刷新演练!














暂无评论内容