Power BI之DAX神功:第3卷第11回 创建计算表的四个常用函数
一、SELECTCOLUMNS函数
《火力全开》笔记26 我们已经对这个函数的语法讲解过了,语法不再重复,现在我们讲原理
【1】SELECTCOLUMNS与SQL语句中的SELECT...From
《火力全开》视频第0集建议大家先学习Access基础篇,我的Access基础篇与PowerBI衔接。让你快速理解什么是数据库(包含数据规范),多表关系如何处理等知识。
假设我们数据库中有这样一张表:

我们想增加一个总分列,如果直接在表中增加,就相当于DAX里面的AddColumns
但是,如果这张表不想让它发生改变,想生成一张新的表,实现增加列就可以使用SELECTCOLUMNS

现在是不是能更好的理解上面这段话了?当我们在数据库的表中选择某列并生成新列,如下图所示:

结果如下:现在你看到的结果和原表有关系没?有关系!是原表吗?不是!

其实将上述过程写成SQL语句:
SELECT 姓名, [平时成绩]*0.3+[考试成绩]*0.7 AS 总分 FROM 表1
现在我们将下面这张表放到PowerBI中,使用我们的DAX函数SELECTCOLUMNS来演示:

公式如下:

DAX语言相比SQL晚了有20多年。DAX语言基于SQL思维,这一点官方是认同的。
【2】SELECTCOLUMNS与SUMMARIZECOLUMNS、SUMMARIZE的区别
《The Definitive Guide to DAX》中声明了它们的区别,我用自己的语言来讲一下:
SELECTCOLUMNS:选择列,添加新列,生成一张新的表。不分组就相当于不去重。
SUMMARIZECOLUMNS、SUMMARIZE:分组!相当于SQL中的Group by,分组必去重。
以下图为例:

同样的公式:
结果不去重:

当我们使用SUMMARIZECOLUMNS或SUMMARIZE时:
结果返回:结果去重,当然这里使用sum只出于教学目的,实战中应该使用Average

当使用Average时:
返回结果:

还是那句话:没有什么时候应该用什么这种说法!你的分析中需要用什么你就选择什么!切记:DAX不能代替人脑,它只是计算工具。
【3】SELECTCOLUMNS在数据沿袭中的应用
《The Definitive Guide to DAX》中只提到一种情况,然而情况有很多种,我在《DAX神功》第2卷第21回 数据沿袭 中做了充分证明,这里我不在重复讲过的内容。我相信看到这里的小伙伴已经看过数据沿袭这节课了。当然你是否还记得那节课讲的是什么,我就不清楚了。
二、创建静态单行表ROW函数【可被表构造函数代替】
《火力全开》笔记24.03中我们介绍了ROW函数的语法
作用:创建只有一行的表(可以是单列或多列)

【度量值】平时总分 = sum(Sheet1[平时成绩])
【度量值】考试总分 = SUM(Sheet1[考试成绩])
新建表3 = row("平时分",[平时总分],"考试分",[考试总分])

注意:新建表中无论使用度量值还是表达式,最终返回的均是一个值。下面的公式用来证明
新建表4 = row("平时分",sum(Sheet1[平时成绩]),"考试分",sum(Sheet1[考试成绩]))

我们可以使用构造表函数代替ROW函数:
新建表5 = {([平时总分],[考试总分])}
新建表6 = {(sum(Sheet1[平时成绩]),sum(Sheet1[考试成绩]))}

《The Definitive Guide to DAX》中指出表构造函数的缺点是不能自定义字段名称,PowerBI中不存在这样的问题:
《DAX神功》第1卷第3回 我们就讲到了这个方法
返回结果:

总结:无论你使用ROW函数还是表构造函数,没有什么区别,开心就好!
三、创建静态表:DATATABLE函数【可被表构造函数代替】
【1】标准语法
《火力全开》笔记16.2中我们讲解了DATATABLE函数的语法
生成单列的表:
返回结果:

生成多列的表:
返回结果:

数据类型:

【2】不要与表构造函数混淆
{{"数据11","数据12"},{"数据21","数据22"}} // 这不是表构造函数

{("数据11","数据12"),("数据21","数据22")} // 这才是表构造函数

表构造函数每个小括号代表一行,大括号代表整张表。
【3】DATATABLE函数只能使用常量,不能使用度量值或表达式
我们刚刚讲ROW函数可以被表构造函数代替时,向大家演示了,表构造函数支持度量值或表达式。(其实度量值也是表达式生成的)
例如表构造函数:
返回结果:

但是在DATATABLE函数中就不可以:
返回错误提示:

注意:DATATABLE 函数限制表的内容必须是常量,不支持任何 DAX 表达式(度量值)。
【4】为什么说它可以被代替我们举例说明

使用Filter反复筛选同一列:
返回结果:但是肯定没人有会这样做。

我们应该怎么做?是不是利用表构造函数?
所以说表构造函数是最简单、最容易理解的。如果我们换成DATATABLE函数结果是一样的。
但你是不是认为这画蛇添足了?还有更绕你的方法:请往下看
新建表12中我们使用in检查一个值是否存在于表中
'Sheet1'[姓名] in {"张三","李四","王五"}
in的等价函数是Containsrow
Containsrow( {"张三","李四","王五"},'Sheet1'[姓名]) // 等价于'Sheet1'[姓名] in {"张三","李四","王五"}
还有另外一个等价函数Contains,《火力全开》笔记24.01中讲过
Contains({"张三","李四","王五"},[value],'Sheet1'[姓名]) // 等价于'Sheet1'[姓名] in {"张三","李四","王五"}
以上等价公式我是使用单列进行举例,如果多列同样可以使用。
接下来我们分步骤实现:
表 = DATATABLE ("人名", STRING,{ { "张三" }, { "李四" }, { "王五" } })

我们使用Containsrow或Contains函数代替in函数:
返回结果:DAX函数就是这样,你想绕,他就陪着你绕。

记住:DATATABLE函数可以被表构造函数代替就可以了。同理Contains和Containsrow大多数情况下也能被in代替。
四、GENERATESERIES函数
《DAX神功》第2卷第6回 我们使用GENERATESERIES函数制作分段排名,例如:每20分一个档位。具体案例大家可以详见这节课。
另外,我们在《PowerBI论数据清洗重要性》这个视频中,也使用了GENERATESERIES函数做生成笛卡儿积表的“助推火箭”!
https://www.bilibili.com/video/BV13R4y1E774?spm_id_from=333.999.0.0
当然,在《The Definitive Guide to DAX》中提到的案例对部分人员非常有价值,对我来说分析就截止到年月日,不涉及小时,分钟和秒。但是有些行业可以利用GENERATESERIES函数生成时间表。如下图所示:

这个时候,我们就可以使用Selectcolumns选择生成新列,同时会用到Format函数
《火力全开》第18课中有Format函数详细语法,你不需要背下来,用的时候去查
// Ps: @二哈到底哈不哈,我使用的是《火力全开》笔记18附1日期格式中的方法,与书中方法不同。但是SELECTCOLUMNS和GENERATESERIES的语法是微软开发的,我无法改变其语法。就好比罗老师讲法,他有自己的讲法,但是法律条文是什么样就什么样,不能改。法律条文就相当于这里的语法。

我们之前可以新建日期表,同理我们现在制作的是时间表,当你放在切片器上就可以有更多选择进行筛选。

《孙兴华讲PowerBI火力全开》PowerBI必学课程
https://www.bilibili.com/video/BV1qa4y1H7wp
《DAX神功》文字版合集:
https://www.bilibili.com/read/readlist/rl442274
《DAX神功》视频版合集:
https://www.bilibili.com/video/BV1YE411E7p3
PowerBI(DAX函数)、PowerQuery(M函数)、Python办公自动化、Python爬虫、Python数据分析、ExcelVBA、WordVBA、AccessVBA、MySQL等等