Power Query:M语言入门与实战技巧

Power Query:M语言入门与实战技巧

 次点击
22 分钟阅读

点鼠标很爽,但写M语言更爽。学会这个,你就是Power Query的高级玩家。


为什么要学M语言?

Power Query的界面操作其实背后都在生成M语言代码。点鼠标能完成80%的工作,但剩下20%的复杂需求,必须写代码。

而且,写代码有写代码的好处:

  • 更灵活:循环、条件、自定义函数
  • 更可控:精确控制每一步的逻辑
  • 更可复用:保存成函数,到处调用
  • 更装逼:同事会觉得你很厉害

M语言基础语法

M语言是大小写敏感的,这点要注意。

基本结构

let
    步骤1 = 操作1,
    步骤2 = 操作2,
    结果 = 最后操作
in
    结果

每个步骤后面加逗号,最后一个步骤不加。

创建表格

let
    源 = #table(
        {"姓名", "年龄", "部门"},  // 表头
        {
            {"张三", 25, "技术部"},
            {"李四", 30, "销售部"},
            {"王五", 28, "技术部"}
        }
    )
in
    源

引用上一步的结果

let
    源 = Excel.CurrentWorkbook(){[Name="表1"]}[Content],
    改类型 = Table.TransformColumnTypes(源, {{"日期", type date}}),
    筛选 = Table.SelectRows(改类型, each [销售额] > 10000)
in
    筛选

常用函数速查

表格操作

// 筛选行
Table.SelectRows(表, each [列名] > 条件)

// 选择列
Table.SelectColumns(表, {"列1", "列2"})

// 删除列
Table.RemoveColumns(表, {"列1", "列2"})

// 重命名列
Table.RenameColumns(表, {{"旧名", "新名"}})

// 添加列
Table.AddColumn(表, "新列名", each 计算公式)

// 排序
Table.Sort(表, {{"列名", Order.Descending}})

列表操作

// 创建列表
{1, 2, 3, 4, 5}

// 序列
{1..10}  // 1到10

// 列表求和
List.Sum(列表)

// 列表平均值
List.Average(列表)

// 列表最大值/最小值
List.Max(列表)
List.Min(列表)

文本操作

// 拼接
Text.Combine({"Hello", " ", "World"})

// 拆分
Text.Split("a,b,c", ",")

// 替换
Text.Replace("Hello World", "World", "Excel")

// 取长度
Text.Length("Hello")

// 取子串
Text.Start("Hello", 2)    // 前2个字符
Text.End("Hello", 2)      // 后2个字符
Text.Middle("Hello", 1, 2) // 从第2位开始取2个

日期时间

// 今天
DateTime.LocalNow()

// 日期部分
Date.From(DateTime.LocalNow())

// 年月日
Date.Year(日期)
Date.Month(日期)
Date.Day(日期)

// 本月初
Date.StartOfMonth(日期)

// 本月末
Date.EndOfMonth(日期)

实战案例1:动态获取最近N天的数据

需求: 只筛选最近30天的记录。

let
    源 = Excel.CurrentWorkbook(){[Name="销售表"]}[Content],
    改日期类型 = Table.TransformColumnTypes(源, {{"日期", type date}}),
  
    // 获取今天
    今天 = Date.From(DateTime.LocalNow()),
  
    // 计算30天前
    起始日期 = Date.AddDays(今天, -30),
  
    // 筛选
    筛选结果 = Table.SelectRows(改日期类型, each [日期] >= 起始日期)
in
    筛选结果

每次刷新,自动计算从今天往前30天的数据。


实战案例2:递归展开多层JSON

场景: API返回的JSON是嵌套的,比如:

{
  "订单": [
    {
      "订单号": "A001",
      "商品": [
        {"名称": "手机", "数量": 1},
        {"名称": "耳机", "数量": 1}
      ]
    }
  ]
}

需要展开成:

订单号 商品名称 数量
A001 手机 1
A001 耳机 1

M语言写法:

let
    源 = Json.Document(获取的JSON),
    订单列表 = 源[订单],
    转表格 = Table.FromList(订单列表, Splitter.SplitByNothing()),
    展开订单 = Table.ExpandRecordColumn(转表格, "Column1", {"订单号", "商品"}),
    展开商品 = Table.ExpandListColumn(展开订单, "商品"),
    展开商品详情 = Table.ExpandRecordColumn(展开商品, "商品", {"名称", "数量"})
in
    展开商品详情

关键步骤:

  1. Table.FromList 把列表转成表格
  2. Table.ExpandRecordColumn 展开记录(对象)
  3. Table.ExpandListColumn 展开列表(数组)

实战案例3:创建自定义函数

场景: 有一个通用的清洗逻辑,要在多个查询里复用。

创建函数

// 命名为:清洗订单表
(订单表 as table) as table =
let
    改类型 = Table.TransformColumnTypes(订单表, {{"日期", type date}, {"金额", type number}}),
    删除空值 = Table.SelectRows(改类型, each [订单号] <> null),
    加提成列 = Table.AddColumn(删除空值, "提成", each [金额] * 0.05)
in
    加提成列

使用函数

let
    原始数据 = Excel.CurrentWorkbook(){[Name="表1"]}[Content],
    清洗后 = 清洗订单表(原始数据)
in
    清洗后

函数可以接收多个参数,返回任何类型。


实战案例4:循环处理文件夹里的文件

场景: 每个文件需要不同的处理逻辑。

let
    源 = Folder.Files("C:\\报表\\"),
    筛选文件 = Table.SelectRows(源, each Text.EndsWith([Name], ".xlsx")),
  
    // 添加处理列,每个文件调用自定义处理
    处理结果 = Table.AddColumn(筛选文件, "处理后的数据", each 
        try 处理单个文件([Content]) otherwise null
    ),
  
    // 展开处理后的数据
    展开数据 = Table.ExpandTableColumn(处理结果, "处理后的数据", 
        Table.ColumnNames(处理结果{0}[处理后的数据])),
  
    // 删除原始二进制列
    删除列 = Table.RemoveColumns(展开数据, {"Content", "Extension", "Date accessed"})
in
    删除列

// 自定义处理函数
处理单个文件 = (文件内容 as binary) as table =
let
    加载 = Excel.Workbook(文件内容),
    第一个表 = 加载{0}[Data],
    提升标题 = Table.PromoteHeaders(第一个表)
in
    提升标题

调试技巧

查看中间结果

在M语言编辑器里,点击某一行,可以看到这步的结果预览。

分步执行

in之前插入一个临时结果:

let
    步骤1 = ...,
    步骤2 = ...,
    调试 = 步骤2,  // 在这里暂停查看
    步骤3 = ...
in
    步骤3

错误处理

try 可能出错的代码 otherwise 默认值

学习资源

  • Power Query官方文档(英文)
  • M语言规范文档
  • 多看点示例代码,比看书有用

一句话总结

M语言是Power Query的底层引擎。点鼠标是自动挡,写M语言是手动挡,开习惯了手动挡更爽。

学会M语言,你就能做出任何复杂的数据处理逻辑,不再受界面操作的限制。


M语言刚看的时候确实有点懵,但语法其实比VBA简单多了。写多了就会发现,它比点鼠标快多了,尤其是处理复杂逻辑的时候。推荐先从简单的函数开始,慢慢就会上瘾的。

© 本文著作权归作者所有,未经许可不得转载使用。