文 / 老汪(汽车零部件财务与商业智能实战派)
专栏:【Excel BI 财务建模实战课讲义(第2阶段)】 · 期数:EP039
核心函数:List.TransformMany/Table.ToRows/Table.FromRows
📌 老汪开篇导读:突破维度壁垒的“笛卡尔积”神技
各位财务伙伴、薪酬核算会计与车间数据统计员:
平时在制造企业里做财务分析,我们绝大多数时候处理的都是一对一(One-to-One)的线型数据流——比如给每一行加个含税单价、给每条工单算个工时。但只要你负责过月末的薪资结算或者生产计划排程,你必然会被下面两类“一对多(One-to-Many)”的结构重构折磨得焦头烂额:
- 车间工资条制作:每个月一线工人的计件工资算出来了,整齐排列在一张大表里。但是车间现场发工资必须打印纸质工资条给工人签字确认!这意味着你必须在每一个工人记录上方插入一行表头,在下方插入一行空白裁切线。网上教的什么“辅助列排序法”、“公式隔行引用法”,只要人员一增减就错位瘫痪;
- 多维度交叉组合(笛卡尔积):比如厂部有 5 大工段,每个工段有 3 种轮班制,每种班制要排 4 道质检工序。很多人在 Excel 里只能一层层手工复制粘贴排列组合,耗时费力还极易漏项。
在 Power Query 的函数宝库中,有一张专门解决“维度交叉组合”与“一对多结构裂变”的终极王牌——List.TransformMany!
今天老汪就以汽车零部件一级供应商(Tier 1)压铸与机加车间的月度一线工人计件工资条生成为例,带大家彻底吃透笛卡尔积的数学底层逻辑,并手把手写出一键秒级自动化生成带表头与裁切线工资条的工业级 M 脚本!
🛠️ 一、 核心函数物理机制拆解
1. 函数语法与参数架构
💡 老汪敲黑板(免改路径直接刷新秘籍):
平时做财务分析最怕换台电脑一刷新就报错“找不到文件路径”。老汪在给各位学员配套的实操课件【配置】表 A1 单元格中预置了自适应公式,大家把本课案例包解压后直接点击 Excel 的【全部刷新】即可秒级重现,绝不报红字!大家可以把这套自适应架构无缝迁移到公司的日常模型中! 实操指南点此篇文章:《实操指南》
List.TransformMany(
list as list,
collectionTransform as function,
resultSelector as function
) as list
| 参数名称 | 参数类型 | 形象代号 | 物理机制与老汪通俗拆解 |
|---|---|---|---|
list |
List | 外层母集合 (x) | 主循环驱动列表。比如传入 100 名工人的记录列表,每次遍历出一个工人 x。 |
collectionTransform |
Function | 内层子集合 (y) | 一对多裂变器。针对当前的 x,返回一个与之对应的子列表集合。比如返回 {表头, x, 空行}。 |
resultSelector |
Function | 结果组装器 (x, y) => z | 终极映射输出。接收外层元素 x 与内层当前元素 y,决定最终打平输出什么。若直接写 (x, y) => y,则直接把内层结果打平! |
2. 笛卡尔积的核心原理与数学图解
假设母列表 $X = {A, B}$,子列表 $Y = {1, 2, 3}$:
通过 List.TransformMany(X, each Y, (x, y) => Text.From(x) & Text.From(y)),执行逻辑如下:
– $x = A$ 时,遍历 $Y$ ➔ 产出 $A1, A2, A3$
– $x = B$ 时,遍历 $Y$ ➔ 产出 $B1, B2, B3$
– 最终结果瞬间打平成一维列表:{"A1", "A2", "A3", "B1", "B2", "B3"}!
元素总个数等于 $2 \times 3 = 6$ 项,这就是经典的高等数学笛卡尔乘积!
🏭 二、 汽车零部件制造业业务场景实战
1. 业务背景
在我们汽车零部件 Tier 1 生产基地(包含精密压铸车间、CNC五轴机加组、机器人焊装班等),每月有大量一线计件工人的薪酬结算。
财务薪酬专员核算出的原始计件工资台账如下:
| 员工工号 | 员工姓名 | 所属车间工段 | 技能等级 | 计件基本工资(元) | 超额计件奖(元) | 满勤夜班津贴(元) | 工装保养改善奖(元) | 社保公积金代扣(元) | 实发税后工资(元) |
|---|---|---|---|---|---|---|---|---|---|
| YG-202601 | 张建国 | 精密压铸一工段 | 高级压铸技师 | 6,800.0 | 1,850.0 | 600.0 | 450.0 | 1,150.0 | 8,550.0 |
| YG-202602 | 李明亮 | CNC数控五轴机加组 | 高级调机师 | 7,200.0 | 2,100.0 | 500.0 | 500.0 | 1,220.0 | 9,080.0 |
| YG-202603 | 王志强 | 机器人激光焊装班 | 特种激光焊工 | 6,500.0 | 1,600.0 | 600.0 | 400.0 | 1,100.0 | 8,000.0 |
| YG-202604 | 赵大宝 | 表面阳极钝化喷涂 | 中级表面处理工 | 5,800.0 | 1,400.0 | 550.0 | 350.0 | 980.0 | 7,120.0 |
| YG-202605 | 孙海鹏 | 底盘总成智能装配 | 装配线技能能手 | 6,200.0 | 1,750.0 | 500.0 | 400.0 | 1,050.0 | 7,800.0 |
| YG-202606 | 周福海 | 三坐标精密质检室 | 高级三坐标质检员 | 6,600.0 | 1,500.0 | 450.0 | 500.0 | 1,120.0 | 7,930.0 |
2. 现场打印需求与痛点
车间主任要求:每名工人必须拥有独立的 3 行打印单元:
– 行 1:清晰的 10 列标题(让工人清楚看到哪一列是基本工资、哪一列是超额奖);
– 行 2:该工人本月的实际金额明细;
– 行 3:一行空行(打印出来作为裁纸刀裁切的留白区)。
如果用 Excel 传统做法,每个月要复制几十次表头并插入空行,只要下个月多了 2 个新员工,公式和格式全得推倒重来。我们现在用 M 语言写一套全动态自适应工资条生成管道!
🚀 三、 老汪手把手推导:三大阶段实现工资条极速重构
阶段一:提取纯净表头与行列表
在我们在上一课(EP038)学过 Table.ColumnNames 和 Table.ToRows:
– 表头字段名列表 = Table.ColumnNames(更改类型):提取 10 个标题名称;
– 按行拆解数据集合 = Table.ToRows(更改类型):将整张表转为 6 个员工行子列表;
– 空裁切行 = List.Repeat({null}, 10):动态生成包含 10 个 null 的占位空行。
阶段二:调用 List.TransformMany 实施结构重构(核心大招!)
我们要把每个员工行 $x$ 变成 3 行,这就是最典型的“1 对 3 笛卡尔积裂变”:
工资条平铺行列表 = List.TransformMany(
按行拆解数据集合,
each {表头字段名列表, _, 空裁切行},
(x, y) => y
)
💡 老汪敲黑板:
1.按行拆解数据集合作为主列表传给第 1 参数;
2.each {表头字段名列表, _, 空裁切行}作为第 2 参数:对于每一个被遍历的员工行_(下划线代表当前行记录),瞬间构建出由 3 个子列表组成的集合!
3.(x, y) => y作为第 3 参数:告诉 PQ 我们不需要对 $x$ 和 $y$ 做文本拼接,直接把内层的每一行 $y$ 依序平铺输出!执行这一步后,原本只有 6 行的员工数据,瞬间被重构为了 $6 \times 3 = 18$ 行包含表头、明细与裁切空行的平铺大列表!
阶段三:还原二维表格并提升首行标题
现在平铺的 18 行只是内存中的嵌套列表,我们调用在 EP038 掌握的 Table.FromRows 还原二维表,并调用 Table.PromoteHeaders 提升第一行作为全局表头:
生成工资条表格 = Table.FromRows(工资条平铺行列表),
提升首行标题 = Table.PromoteHeaders(生成工资条表格, [PromoteAllScalars=true])
最终生成的车间工资条效果如下(部分展示):
| 员工工号 | 员工姓名 | 所属车间工段 | 技能等级 | 计件基本工资(元) | 超额计件奖(元) | 满勤夜班津贴(元) | 工装保养改善奖(元) | 社保公积金代扣(元) | 实发税后工资(元) |
|---|---|---|---|---|---|---|---|---|---|
| YG-202601 | 张建国 | 精密压铸一工段 | 高级压铸技师 | 6,800.0 | 1,850.0 | 600.0 | 450.0 | 1,150.0 | 8,550.0 |
| ✂️ ————————— [ 裁 切 线 ] ————————— | |||||||||
| 员工工号 | 员工姓名 | 所属车间工段 | 技能等级 | 计件基本工资(元) | 超额计件奖(元) | 满勤夜班津贴(元) | 工装保养改善奖(元) | 社保公积金代扣(元) | 实发税后工资(元) |
| YG-202602 | 李明亮 | CNC数控五轴机加组 | 高级调机师 | 7,200.0 | 2,100.0 | 500.0 | 500.0 | 1,220.0 | 9,080.0 |
| ✂️ ————————— [ 裁 切 线 ] ————————— | |||||||||
💡 老汪敲黑板:工业级实战避坑三要诀
- 第三参数的映射陷阱:
很多人在写(x, y) => ...时容易晕掉。请记住口诀:x 是外层大集合的当前元素,y 是内层裂变后子集合的当前元素。如果只是为了打平插入,直接写(x, y) => y;如果需要拼接编码(如工号+工序代码),则用Text.From(x) & "_" & Text.From(y)。 - 空行的列数对齐铁律:
空裁切行 = List.Repeat({null}, List.Count(表头字段名列表))必须严格采用动态计数List.Count!因为Table.FromRows对每一行的元素个数有强校验,如果空行少了一个null,整个查询会立即崩溃报错! - Q001 动态相对路径机制(免改路径直接刷新秘籍):
平时做财务分析最怕换电脑报错,老汪已经在随堂课件的【配置】表写好公式,大家解压到任意电脑或工位,直接点击【数据】➔【全部刷新】即可,绝不报红字路径不存在!
🎁 随堂实操课件包下载
本节课专属配套实操资产已全量打包,包含:
1. 《原始业务数据表.xlsx》:车间一线计件工人月度薪酬台账原始数据;
2. 《最终完成版_带PQ查询.xlsx》:内嵌 Q001 自适应配置表与自动生成带表头与裁切线工资条的标准报表;
3. 《M_动态自适应脚本.m》:标准工业级 M 语言核心脚本(含详细中文逐行注释);
4. 《PowerQuery随堂实操课件学员使用与M脚本演练指南.docx》:【学员必备实操指引】手把手带您新建空白查询、注入 M 脚本并单步回溯演练。














暂无评论内容