WPS Query之浅谈类型
| 💡 | 下文中Wps Query简称WQ,Power Query简称PQ。 |
| 💡 | 截止目前(202608)WQ并未开放文档,本文更多基于PQ的经验来描述相关内容。 |
前言
WQ/PQ使用m语言运行,m语言使用强类型。之所以为强类型是因为PQ前后端经常会遇到数据库,除了常见的数字、日期等类型外,为了兼容数据库还设计了更细分的整数、货币等用以方便将数据导出到数据库,另外还有惰性计算和折叠等机制来提高性能。
分类
目前PQ中对用户开放的类型有any、anynonnull、binary、date、datetime、datetimezone、duration、function、list、logical、none、null、number、record、table、text、time、type。
| 💡 | 绿色标记是经常会遇到的类型,黄色标记是不太常见或稍微有点难以理解的类型,其它为不需要关注的类型。 |
类型兼容
any类型是一个特殊的类型,它兼容所有的值。对于表达式1 is number毫无疑问是true,同时1 is any也是true,包括null is any也是true。
如果您翻阅过PQ文档中关于is关键字的描述:
测试类型是否兼容基本类型或可为空的基本类型
基于is关键字的描述,我们可以说any类型兼容1,但不能说1是any类型。
| 💡 | any类型并不存在实际的对应值,但它兼容所有值。 |
在WQ/PQ中,当程序推测到列中存在多种类型时,m引擎会自动将列类型设为any。比如下图这种图标就表示any类型:
对应的查询内容如下:
let
源 = Excel.Workbook(File.Contents("C:\Users\Black\Desktop\wq测试.xlsx"), null, true),
导航 = 源{[Name = "Sheet1"]}[Data],
提升的标题 = Table.PromoteHeaders(导航, [PromoteAllScalars = true]),
修改列类型 = Table.TransformColumnTypes(提升的标题, {{"类型测试", type any}})
in
修改列类型转换列类型
当用户点击列左上角的类型图标转换类型后,m引擎调用Table.TransformColumnTypes函数对指定的列进行类型转换,但这里发生了两步:
使用对应的.From函数转换值,比如:A列指定为小数,那么会使用Number.From函数对A列的所有值进行转换
标记指定列的类型为设置的类型
| ❗ | 截止完帖,WQ中的日期类型还无法正确转换"20260807"这种日期,但Date.From函数可以正常转换。这是一个bug,后续应该会修复。 |
| ❗ | 很多转换函数都支持指定区域设置,如果您涉及国际业务,这很重要!
|
当用户转换列类型时会先转换值类型再设置列类型,然后列图标变成了对应的类型图标,因此很多用户会错误的认为图标(列类型)就是实际的列类型,这是一个误区:PQ界面中表列左上角的类型在PQ中并不能约束列的类型。具体如下图所示:
| 💡 |
|
PQ和WQ中,当用户添加新列后,不会指定类型(即默认any):
在当前PQ和未来WQ开放编辑栏后,如果用户能够确定列类型,则可以手动指定类型。
| 💡 | 手动指定类型需要用户有足够的自信,因为Table.Column中指定类型并不会对列中的值进行类型转换,因此它可能影响后续步骤的结果。但在最终导出结果时还会进行一次数据转换,具体见下一小节。 |
可为空类型
在阅读转换列类型小节时不知道大家都是思考过一个问题:如果将列设置为数字,而列中的null转换后为何没有报错?在解释Table.TransformColumnTypes执行时,第一步是:
由于.From函数的机制就是如果输入null则输出null,因此最终可以得到null。
WQ/PQ中,类型可以使用nullable关键字修饰类型来表示该类型兼容null值,常见的能够很容易看出来区别的是函数:
// 正确,因为123属于number类型
((a as number) => a)(123)
// 错误,因为null不属于number类型
((a as number) => a)(null)
// 正确,因为nullable修饰的类型兼容null
((a as nullable number) => a)(null)| 💡 | 在完成帖子时,WQ还存在显示BUG,上述表达式可以在条件列中执行,但如果编辑会出问题:
|
数据导出
前文提到:
列类型在WQ/PQ中并非约束,而是在导出(或叫上传)数据时由接收端根据类型进行处理。
当我们将设置了类型的列上传后,接收端会对按指定类型进行检查和转换(如果是any类型则会检查最大的兼容类型)。比如前文中未设置类型的例子:
由于表格能够兼容例子中的类型,因此会原样输出(例子中的FALSE为字符串)。由于不兼容错误,如果存在错误就会显示为空白。
| ❗ | 这种转换机制并非是万无一失的,极端情况下会转换成错误的结果。 |
但如果上传到PP(Power Pivot)中,PP接收到any类型后会检查所有值,找出合适的类型并转换值的类型,这个例子会将列中的所有值导出为文本格式,因为PP不支持混合类型的列。
一些建议
虽然WQ与PQ尽量保持兼容,但因为现不同,目前发现有些极端情况会出现不同结果,在转移平台时请谨慎检查。为了避免这种极端,请务必选择合适的类型:仅需要日期就不要使用日期时间,需要货币就不要使用小数。
关于具体的类型及可能出现的不兼容会在以后的帖子中详尽讲解。
