文 / 老汪(汽车零部件财务与商业智能实战派)
专栏:【Excel BI 财务建模实战课讲义(第2阶段)】 · 期数:EP043
核心函数:Table.Skip/Table.PromoteHeaders/Table.TransformColumnTypes
📌 老汪开篇导读:车间报表里的“牛皮癣”与流式截断黑科技
各位财务同仁、成本会计、往来核算BP与产线数据分析师:
在咱们汽车零部件制造企业(Tier 1 一级供应商)的一线财务分析工作中,大家从 SAP、用友、金蝶或者车间 MES 生产制造执行系统里导出流水账单时,经常会遇到以下两类让人血压飙升的“数据恶疾”:
- 恶疾一:报表顶部的“牛皮癣垃圾行”:
系统导出的报表最顶端,往往横七竖八地堆着好几行非结构化说明,比如“【内部保密资料】安徽万向底盘精工制造有限责任公司”、“导出时间:2026-11-09 14:30:22”、“筛选条件:全部车间”、“制表人:老汪”……直到第 5 行才是真正的业务表头!初学者如果直接提升标题,整张表立即报废。 - 恶疾二:前置历史结算数据的“断头截断诉求”:
在主机厂(如比亚迪、吉利、理想)的发货对账与挂账清单中,排在表格前面的往往是试制样件批次(OTS/PPAP 阶段,早已单独结算结清),后面紧接着才是真正需要咱们财务本月重点盯防的量产(SOP)未结清批次。很多同学第一反应是用Table.SelectRows去做多重筛选,但一旦遇到复杂的“前缀连续跳过、遇到首个未结清即停止”的业务逻辑,普通的行筛选就完全无能为力了!
今天老汪要传授给各位的,就是专门用来做表格流式头部截断与动态修剪的屠龙利刃——Table.Skip!
🛠️ 第一部分:老法师拆解底层——Table.Skip 双形态全景解密
Table.Skip 是 Power Query M 引擎中专门用于从表格顶部向下丢弃行记录的函数,它支持固定行数跳过与动态条件谓词跳过两大形态:
Table.Skip(table as table, optional countOrCondition as any) as table
1. 核心参数与运作机理
- 第一参数
table:目标数据表。 - 第二参数
countOrCondition(可选): - 缺省不填:默认跳过第 1 行,等价于
Table.Skip(table, 1); - 传入整数数值(
count as number):精准截断并丢弃表格顶部的 N 行记录。比如Table.Skip(table, 4),直接把前 4 行垃圾信息切掉; - 传入条件谓词函数(
condition as function):传入形如each [字段] = 某个值或复合逻辑表达式。
2. 🚨 老汪敲黑板:学员最高频的致命认知误区!
⚠️ 高危预警:很多从 SQL 或 Excel 筛选思维转过来的同学,往往把
Table.Skip(table, each [状态] = "已结清")误当成“把整张表中所有状态等于已结清的行全部删掉”。
大错特错!
Table.Skip属于数据流式处理中的SkipWhile机制:它从表格第 1 行开始自上而下逐行扫描,只要条件成立(返回true),就跳过该行;但是,一旦遇到第一行让条件为false的记录,扫描立即彻底停止,后续剩下的所有行哪怕完全满足条件,也绝不再跳过,而是 100% 完整保留!
理解了这一底层机理,你才能真正掌握它在处理“有序批次流”、“工序前缀清洗”时的降维打击威力。
🏭 第二部分:汽车零部件制造业发货结算看板实战
1. 业务背景与原始数据表结构
我们以一家为新能源汽车主机厂配套的底盘零部件制造企业为例。成本与往来会计老汪从 MES 系统导出了《底盘件发货结算流水》:
– 顶部前 4 行为系统说明与制表信息(垃圾行);
– 第 5 行是标准表头;
– 前 3 行数据(第 6~8 行)是早期 OTS/PPAP 样件测试批次,且挂账结算状态为“已全部结清”;
– 从第 4 行数据开始,进入本年度 SOP 量产阶段,包含“待对账挂账”、“未开票挂账”、“部分开票未回款”等关键资金沉淀批次。
💻 第三部分:随堂课件完整 M 脚本工程实现
💡 老汪敲黑板(免改路径直接刷新秘籍):
平时做财务分析最怕换台电脑一刷新就报错“找不到文件路径”。老汪在给各位学员配套的实操课件【配置】表 A1 单元格中预置了自适应公式,大家把本课案例包解压后直接点击 Excel 的【全部刷新】即可秒级重现,绝不报红字!大家可以把这套自适应架构无缝迁移到公司的日常模型中! 实操指南点此篇文章:《实操指南》
// =========================================================================
// 专栏:【Excel BI 财务建模实战课讲义(第2阶段)】· EP043
// 模块:Table.Skip 跳过指定行数与按条件动态截断(表头垃圾清理与分段截取)
// 讲师:老汪(汽车零部件财务与商业智能实战派)
// =========================================================================
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」中 MES 导出的发货结算流水
// ---------------------------------------------------------------------
数据文件路径 = 当前目录 & "原始业务数据表.xlsx",
源文件 = Excel.Workbook(File.Contents(数据文件路径), null, true),
原始明细表 = 源文件{[Item="MES系统导出_底盘件发货结算流水", Kind="Sheet"]}[Data],
// ---------------------------------------------------------------------
// 步骤 3:核心技法 1 ——【Table.Skip 数值形态】跳过顶部 4 行非结构化垃圾行
// 说明:MES 系统导出的前 4 行是标题、导出时间、统计期间等说明文字,不是真正表头
// ---------------------------------------------------------------------
跳过顶部垃圾行 = Table.Skip(原始明细表, 4),
// ---------------------------------------------------------------------
// 步骤 4:将第 5 行提升为标准业务字段表头
// ---------------------------------------------------------------------
提升的标题 = Table.PromoteHeaders(跳过顶部垃圾行, [PromoteAllScalars=true]),
// ---------------------------------------------------------------------
// 步骤 5:类型规范转换
// ---------------------------------------------------------------------
更改的数据类型 = Table.TransformColumnTypes(提升的标题, {
{"发货批次号", type text},
{"所属产线", type text},
{"核心零件名称", type text},
{"主机厂客户", type text},
{"批次类型", type text},
{"发货状态", type text},
{"发货数量(件)", Int64.Type},
{"单件合同价(元)", type number},
{"批次发货金额(元)", type number},
{"挂账结算状态", type text}
}),
// ---------------------------------------------------------------------
// 步骤 6:核心技法 2 ——【Table.Skip 条件形态】按条件连续动态截断
// 业务逻辑:跳过排在前面的样件试制阶段(OTS/PPAP)或已全部结清的历史批次,
// 一旦遇到第一行量产(SOP)且未结清的流水,立即停止跳过,保留后续全部数据!
// ---------------------------------------------------------------------
动态跳过历史已结清批次 = Table.Skip(
更改的数据类型,
each ([批次类型] = "OTS样件试制" or [挂账结算状态] = "已全部结清")
)
in
动态跳过历史已结清批次
📊 第四部分:清洗前后数据效果对照表
通过 Table.Skip 的两级管道组合清洗,原本混杂了前置文本噪音与历史陈旧批次的原始表,秒级重构为干净纯粹的量产发货管理大表:
🚦 第五部分:老汪实战避坑指南(三大血泪经验)
1. 动态跳过空行的工业级防爆写法
很多 ERP 导出的表格顶部垃圾行数是不固定的(有时候导出来 3 行说明,有时候导出来 5 行)。如果你写死了 Table.Skip(源, 4),下个月换个账期可能第一行就是有效数据,直接把数据给切掉了!
💡 老汪推荐动态跳法:
// 只要第一列是空值,或者包含“公司/导出”字样,就一直跳过,直到遇到真正的列头关键字!
动态跳行 = Table.Skip(原始明细, each [Column1] = null or Text.Contains([Column1], "公司") or Text.Contains([Column1], "导出"))
2. 避免在未显式类型转换前进行数值大小比较
如果直接对从 Excel 抓进来的原生文本执行 each [发货数量] > 1000,由于此时字段默认为 any 或 text,M 引擎在比较大小时可能导致不可预测的比较异常或抛出 Expression.Error。务必先通过 Table.TransformColumnTypes 固化数值类型再进行谓词比较!
3. Table.Skip 与 Table.SelectRows 的精准分工
- 如果需要截除连续的头部阶段(如只截掉开头的测试样件),必须用
Table.Skip; - 如果需要把分散在表格各处的所有“已结清”记录无论位置一律剔除,则必须使用
Table.SelectRows。二者配合,才是高手的数据清洗流水线!
🎁 老汪结语与随堂课件包下载
掌握了 Table.Skip,从今往后面对任何 ERP 导出带有各类奇葩前置标题、多余说明行或需要动态截断连续前缀的历史流水,你都可以在 M 语言中一笔搞定,再也不用手动去逐行删除!















暂无评论内容