ADDCOLUMNS 返回包含原始列和所有新添加列的表。由于新列使用的标量表达式沿着第一参数的每行计值,所以 ADDCOLUMNS 也是迭代函数。
例如,你可以使用以下语法添加两列,计算每个产品类别下的子类别数量和产品的数量:
EVALUATE ADDCOLUMNS ( 'Product Category', "Subcategories", CALCULATE ( COUNTROWS ( 'Product Subcategory' ) ), "Products", CALCULATE ( COUNTROWS ( Product ) ) )
结果包括产品类别表中的列和由 ADDCOLUMNS 迭代计算的列。你可以看到这些新列以斜体突出显示。
稍后你将看到原生列和派生列(上图中以斜体显示)重要区别。斜体显示的列无法映射模型中物理列的沿袭(Lineage),并且你不能在筛选上下文中使用它们,我们将在 DAX 高级原理的“理解沿袭”一文中做更详细地描述。
仔细观察上面的查询,你会发现两个派生列的公式都使用了 CALCULATE,它的作用是激活上下文转换,将 ADDCOLUMNS 创建的行上下文转换为筛选上下文。如果去掉 CALCULATE,查询将无法得到预期的结果
迭代函数
ADDCOLUMNS 是一个迭代函数,它创建行上下文,在表的每一行计算用于添加列的表达式。换句话说,ADDCOLUMNS 为你提供了和计算列相同的语义,但是计算的结果属于本地查询的缓存,而不是数据模型中的持久结果。也因为这个原因,你可以调用其他迭代函数(例如 FILTER 或其他 ADDCOLUMNS)获取 ADDCOLUMNS 的新列中的结果,但不能在 CALCULATE 或 CALCULATETABLE 中将这些列用作筛选器参数。
例如,通过对 ADDCOLUMNS 调用 FILTER 函数,你可以筛选出至少有 500 个产品的类别,如下面的示例所示:
EVALUATE FILTER ( ADDCOLUMNS ( 'Product Category', "Subcategories", CALCULATE ( COUNTROWS ( 'Product Subcategory' ) ), "Products", CALCULATE ( COUNTROWS ( Product ) ) ), [Products] > 500 )
这一次的结果只包含很少的行
使用 ADDCOLUMNS 代替 SELECTCOLUMNS
如果你需要从表中选出列的子集,可以使用 SELECTCOLUMNS,下一篇文章将介绍此函数。不过,旧版的 DAX 没有 SELECTCOLUMNS 函数,只能使用 ADDCOLUMNS 来获得需要的结果。在这种情况下,第一参数应该只包含一个或多个列,目的是标识表的唯一行,然后添加所需的列。例如,如果你希望从产品表中获得一个只有三列的表:ProductKey, Product Name 和 Unit Price,可以使用以下查询:
EVALUATE ADDCOLUMNS ( DISTINCT ( Product[ProductKey] ), "Product Name", CALCULATE ( VALUES ( Product[Product Name] ) ), "Price", CALCULATE ( VALUES ( Product[Unit Price] ) ) )
请注意,结果里只有 ProductKey 列映射到物理表,其他两列是派生列(以斜体显示)。派生列在筛选上下文中存在重要的限制:你不能通过筛选上下文筛选派生列。为了避免这种情况,最好尽可能使用 SELECTCOLUMNS 来选择和创建需要在结果中投影的列。
EVALUATE
ADDCOLUMNS (
DISTINCT ( Product[ProductKey] ),
“Product Name”, CALCULATE ( VALUES ( Product[Product Name] ) ),
“Price”, CALCULATE ( VALUES ( Product[Unit Price] ) )
)
老师,这个地方不理解, 数据沿袭那章说VALUES不会改变列的数据沿袭,这里为什么就改变了列
老师好,关于这一句:
”仔细观察上面的查询,你会发现两个派生列的公式都使用了 CALCULATE,它的作用是激活上下文转换,将 ADDCOLUMNS 创建的行上下文转换为筛选上下文。如果去掉 CALCULATE,查询将无法得到预期的结果“,
我把先在数据模型中建立一个度量值为 Subcategories=COUNTROWS ( ‘Product Subcategory’ ) ),然后把这个函数:
EVALUATE
ADDCOLUMNS (
‘Product Category’,
“Subcategories”, CALCULATE ( COUNTROWS ( ‘Product Subcategory’ ) ),
“Products”, CALCULATE ( COUNTROWS ( Product ) )
)
修改为:
EVALUATE
ADDCOLUMNS (
‘Product Category’,
“Subcategories”,[Subcategories],
“Products”,COUNTROWS ( Product )
)
发现添加的派生列去掉CALCULATE后,新添加的”Subcategories”列和没有去掉CALCULATE的效果一样,而”Products”显示的是全部的数据,请问是因为引用的度量值可以直接转换为筛选上下文吗?
通过高飞老师的指导点拨,我又在想之前的这个例子中为什么先直接使用selectcolunms选择的列组成的表,再去添加列的时候怎么都添加不了的问题,然后找出解决办法。其实对我自己而言,肯定觉得先选择列再添加列会更自然(先减后加的感觉,仿佛计算量会小一点,不过事实上好像并非一定会计算更快)。我的理解是这样的,selectcolumns选择的派生列构成了新的虚拟表,以虚拟表做addcolunms的表参数的时候,不能使用原始表中的related关系,这个时候需要使用虚拟关系的treatas之类的函数来创建关系。但是在使用treatas的时候需要用到values函数获取某一列的当前行,因为values需要完全限定名作为参数,所以这一列会引用物理表中的某一列,而不能使直接使用虚拟表的某一派生列,最外层的calculate的作用就是让values取值的时候强制把派生列所组成得虚拟表得当前行值转换成筛选条件,因为扩展表的理论,虚拟表的当前行值条件可以去筛选物理表,从而获得物理表与虚拟表对应的对应的values的单个值。其实根本原因还是在于vlaues的参数需要完全限定名做参数,就导致了不能去直接把虚拟表的某一派生列作为vlaues的参数,不然的话应该不需要两层calculate才能解决问题,不知道我的理解是不是准确。因为理论确实太抽象了,结果得到了也不一定能把过程理解准确。还请高飞老再看看这个查询。
学习这个函数以后,发现其实生活工作中会遇到一种情形,就是物理表中,没有某一列,但是在具体某一次分析过程中需要添加一列作为筛选条件,因为这个分析是一次性的,不具备共性,所以不考虑在模型中去添加列。在工作表中,可以通过添加到列直接创建数据透视表,接着分析,不过在这里面因为沿袭的问题,情况变得复杂很多。我的例子是,我有一个人员信息表,里面有人员的姓名,身份证号(key列),还有民族列,但是突然要求按照民族包含“藏族”字段的分类为”当地”,”非藏族”的是分类为”外地”,按照年份和当地外地对人员进行非重复计数。因为按照addcolumns的属性,添加列不具备沿袭的功能,这个时候想要去用当地外地这一信息对原始表进行分类汇总有比较简单的方法实现吗?
我自己尝试了一下,table2通过筛选出当地的外地的数据,最后通过union合并两个表格数据,倒是达到效果了,不过实现起来太麻烦了,有没有更简单一点的方法,table1通过添加自定义列,然后就进行不下去了,因为添加列不能作为分组的依据。
麻烦解惑,感谢!
本节的【提示】部分是不是与上一节【提示】部分有矛盾,或者说,两个的区别是什么?