M 语言或者叫 M 查询语言是 Power Query (简称为 PQ) 幕后的英雄。据说 Power Query Editor 可视化操作可以实现 PQ 80% 的功能,所以从操作层面来说,大部分人不用学习 M 语言,但学习和掌握 M 语言无疑是在数据处理的时候如虎添翼,而且,有一些 M 的基础也能加深对 PQ 操作步骤的理解,进而有可能对这些应用的步骤做一些优化和改善。总的来说,M 是一种值得学习和掌握的技能,Excel 和 Power BI 都可以用。
创建空查询 (blank query)
前面我们都是连接外部数据源,然后双击 Excel Sheet 右边的查询名称进入Power Query查询编辑器,今天介绍如何通过创建一个空查询的方法进入查询编辑器。有两种方法创建空查询:
- 方法一:切换到【数据】选项卡,然后通过【获取数据】- 【自其他源】- 【空白查询】的方式,Excel 创建一个空白查询,打开并进入到Power Query 查询编辑器。
- 方法二: 先通过【获取数据】- 【启动 Power Query 查询编辑器】进入到Power Query 查询编辑器界面,然后在编辑器界面中创建空查询。
高级编辑器
M 语言代码在进入查询编辑器后,【主页】和【视图】两个选项卡,都有“高级编辑器”按钮,点击即可进入。对于空查询来说,进入后的界面是下面这样:
本篇我们就将通过这个高级编辑器,来了解 M 语言的基础知识。我们假设读者已经有其他编程语言的概念,如果没有其他编程语言的使用经验,建议参考其他文章或书籍了解一下编程语言的概念,比如变量,语句,程序语言的结构等等。
let 语句
个人理解,let 语句的主要作用是配合 PQ 编辑器,方便看到查询中的每一个步骤的公式和结果。比如,我们写在高级编辑器中写一个简单的语句:
点击完成按钮,编辑器显示如下:
在右边应用的步骤中,编辑器把 a、b 和 result 都当做一个步骤,点击其中的某一个步骤,中间的公式栏 (Formula bar) 分别显示出这一个步骤的公式。
let 语句可以很复杂,但我这个理解应该不会有太大的问题。
标识符命名规范
Power Query M 是一种格式自由,但区分大小写的语言,所以标识符命名也要区分大小写,除此之外,其他限制比较少:
- 以非数字、非符号开头(下划线 (_)除外),可以是字母或汉字
- 名称中只能用下划线(_)和点(.)进行分割,如果标识符中出现其他的符号,在标识符前加上
#
符号,比如#year/month
数据类型
理解 M 语言,应该从数据类型开始。M 的数据类型可以分为基本类型和容器类型,基本类型的分类如下:
Text (文本)
M 语言的 Text 用双引号来引导,比如
"Hello World"
因为 M 的 Text 只能用双引号引导,如果 Text 中含有双引号的时候,需要在双引号前面再加上一个双引号,与 VBA 相同。比如要想表达:Tom said: "I love playing football very much",这句话包含两个双引号,在 M 语言中变成了:
result = "Tom said: ""I love playing football very much"""
结尾处,因为 Text 本身需要双引号来包含,所以 much 后面的双引号还有两个双引号,看起来真是令人混淆。
M 语言有三个转义字符(escape sequence)
-cr: Carriage Return
-lf: Line Feed
-tab: Tab
如果在 Text 中需要换行,tab 键等,用 #(escape_sequence)
来表达。比如:
"Hello#(tab)Alice"
"Hello#(cr)#(lf)World"
一个换行,竟然要用两个 # 号,为了简化,连续的转移字符可以下面这样表示:
// 与 "Hello#(cr)#(lf)World" 相同
“Hello#(cr, lf)World”
文本之间用 &
连接:
let
count = 5,
result = "You have " & Text.From(count) & " times left"
in
result
M 语言在进行文本连接的时候,并不能隐式转换 (implicit conversion)。数字可以用 Text.From()
函数转换为文本。
Number
数字字面量可以是 10 进制,也可以是 16 进制。以下是一些数字表示的示例:
5 // 整数
0
0.5 // 小数
1.5e+8 // 指数形式
1.6e-6
1.6E-6 // e 可以大写或者小写
.5 // 合法省略小数点
0xff // 16 进制, 字母可以大写或者小写
0XFF
特殊数字
M 语言中有如下几个特殊数字:
#infinity // produced by an expression like 1/0
#nan // produced by an expression like 0/0
-#infinity // produced by an expression like -1/0
日期类型知识点比较多,单独放一篇吧。