Power BI之DAX神功:第3卷第4回 ADDCOLUMNS函数 你不一定会用
《孙兴华讲PowerBI火力全开》第26课 我们学习了ADDCOLUMNS函数
今天我们细讲这个函数的原理


一、只能应用于新建表,不能应用于新建列
ADDCOLUMNS函数返回的是一张表,当然是表函数了,可是抬扛的人会说没讲原理,那就讲原理呗,满足哈罗雷球白夕尚*的需求。
【1】新建表
新建表1 = ADDCOLUMNS('花名册',"总分",CALCULATE(SUM('成绩表'[分数])))
// CALCULATE(SUM('成绩表'[分数])) 可以使用度量值代替,例如:总分数=SUM('成绩表'[分数])

新建表2 = ADDCOLUMNS(VALUES('花名册'[姓名]),"总分",CALCULATE(SUM('成绩表'[分数])))
新建表2 = ADDCOLUMNS(DISTINCT('花名册'[姓名]),"总分",CALCULATE(SUM('成绩表'[分数])))

注意:ADDCOLUMNS是迭代函数,是行上下文,迭代第1参数那张表的每一行所有列。
所以第3参数,必需具有筛选功能才能适配每一个姓名,要么我们使用度量值,要么就套上calculate进行上下文转换。
如果我们没有转换第三参数,就会显示所有人员成绩总和:5+7+9=21
新建表3 = ADDCOLUMNS(DISTINCT('花名册'[姓名]),"总分",SUM('成绩表'[分数]))

【2】不可以应用于新建列
【错误】新建列 = ADDCOLUMNS('花名册',"总分",CALCULATE(SUM('成绩表'[分数])))

这里要搞清楚新建表和新建列的区别:
新建表的计算顺序:

新建列的计算顺序:

我们上图使用Addcolumns返回了一张多行多列的表,它不转成标量值。《DAX神功》第1卷第10回 将表用作标量 中我们讲过的知识,如下图所示:只有一行一列一个单元格的表才能转成标量值

那应该怎么做?
新建列 = CALCULATE(SUM('成绩表'[分数]))
或者写成
【度量值】总分数=SUM('成绩表'[分数])
新建列=[总分数]

计算原理:

二、可以增加多个计算列并实现筛选
【度量值】总分数=SUM('成绩表'[分数])
【度量值】平均分=AVERAGE('成绩表'[分数])
【新建表】新建表 = ADDCOLUMNS('花名册',"总分",[总分数],"平均分",[平均分])

新建表1 = filter(ADDCOLUMNS('花名册',"总分",[总分数],"平均分",[平均分]),[平均分]>3)

新建表2 = FILTER('花名册',[平均分]>3)
// 不使用Addcolumns我们也能找到符合条件的人,但是不能显示添加的列

三、使用 ADDCOLUMNS 代替 SUMMARIZECOLUMNS
因SUMMARIZECOLUMNS不能应用于大多数度量值,所以我们使用SUMMARIZE+ADDCOLUMNS的组合来实现。
详见《DAX神功》第1卷第15课
四、网友提问
问:《权威指南》关于这一节的计算占销售额15%的产品集合,看不懂。
答:受中西方文化的影响,此问题他标题描述不到位,但是人家下面有步骤说明,你看他过程应该能猜出来意思的。下图是我在Excel中进行的数据模拟

如上图所示,
1.前两列是原始表,我在Excel中算出销售这一列的总和是465,新建总销售这一列,全部填充465。
2.用每个商品的 销售 / 总销售 = 每个商品销售的占比。再找出占前15%的商品。此案例我故意将销售从1至30从小到大排列,这样它肯定是从最后开始取6.24%+6.45%=12.69%,所以就取A29和A30。
3.右边是我找到的规律,只要找到比销售当前行大的所有行求和再除以465,少于15%的就是我要的。
4.我跟大家一再重复,一道题你人不会做,计算机就不会做,你可能会说,我要会还学DAX干嘛?我回复有这种想法的人:如果DAX能代替你,还要你干嘛?
5.数据分析,至少要有小学数学基础(不是会考试,是真的懂),你忘记了数学知识,是因为你工作中用不到,我英语发音也忘光了,因为我用不到。大家的脑袋都差不多,谁也不可能将所有东西都装进去,但是选择装什么内容,是自己决定的。有一些人喜欢抬扛,他们说科学家口语好,数学也好,请问科学家打游戏吗?普通人能与科学家比吗?你为何没成为科学家呢?如果人人都是科学家,那PS/XBOX/SWITCH/企鹅...这些在国内就没销售了。

我们一步一步通过测试做出结果:
第1步:建立度量值
分配销售 = sum(Sheet3[销售])
第2步:新建表,取商品列不重复值构成的表,添加销售列,将度量值分配给每一个值
// 我们只需要商品列,所以要用Values(列)或DISTINCT(列),同时也能杜绝因商品列有重复值时造成的错误。这一步好比Excel函数中的 sumif

第3步:从第一行开始,凡是比当前行销售大的表,就统计他的销售总计是多少,写在新建列移动总计上面。
Var y=tb1[销售] 指当前行指定单元格 《DAX神功》第1卷第14回
filter(tb1,tb1[销售]>=y) 筛选tb1中销售列大于等于当前行销售单元格值的所有行
sumx(表,表达式) => sumx(筛选后的表,指定列) => 对筛选后的这张表指定列求和

第4步:这一步我们只是测试
懒惰计算:详见《DAX神功》答网友问04

我们使用移动总计除以测试,就得到了百分比:跟我在Excel里推导的结果是一样的

第5步:筛选百分比小于等于15%的

tb3是我们测试让你看到效果用的,实际使用中,tb3是可以省略的


孙兴华讲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等等