06.1 理解FILTER


# 初识迭代函数 广义的迭代是对反馈过程的重复,其目的通常是为了接近并到达所需的目标或结果。每一次对过程的重复被称为一次“迭代”,而每一次迭代得到的结果会被用来作为下一次迭代的初始值。在DAX中,迭代函数可以迭代一张表,为表的每一行执行相同的DAX表达式,然后根据不同的函数执行不同的后续操作。DAX的迭代函数数量很多,包括以X结尾的所有聚合函数,比如SUMXAVERAGEX;包括FILTER、ADDCOLUMNS、RANKX等函数,它们都可以创建行上下文。本章我们介绍FILTER和以X结尾的聚合函数。# 理解FILTER FILTER函数的作用很简单:它获取一个表并返回一个与原始表具有相同列的表,逐行应用筛选条件,最后返回满足筛选条件的行。## FILTER语法 FILTER (

, )FILTER迭代整张表
,为每一行计值布尔表达式,当计值结果为TRUE,FILTER返回当前行;否则,就跳过当前行。从逻辑角度来看,FILTER为表中的每个行计值条件表达式。但是,DAX 的内部优化逻辑可能会将这些计算的数量减少到条件表达式中包含的列的唯一值的数量。条件表达式的实际计算次数对应于FILTER操作的“粒度”(granularity)。这个粒度决定了FILTER的性能,它是 DAX 优化的重要因素。例如,下面的查询筛选出产品表中的Fabrikam 品牌EVALUATEFILTER(Product,Product[Brand]=”Fabrikam”)06.1 理解FILTER - 图1只筛选Fabrikam品牌的产品## FILTER嵌套 可以将对FILTER的调用嵌套在另一个FILTER函数中,因为任何返回表的表达式都可以用作FILTER的参数。最内层的FILTER首先执行。通常,嵌套两个筛选器与用AND函数包含逻辑条件的结果相同。换言之,以下查询产生相同的结果:FILTER(
,AND(, < condition2>))FILTER(FILTER(
, < condition1>), < condition2>))但是,如果表有许多行,并且两个条件具有不同的复杂性,则可能会观察到不同的性能。例如,考虑下面的查询,它返回的单价是单位成本的三倍以上的Fabrikam 产品,如下图所示。EVALUATEFILTER(Product,AND(Product[Brand]=”Fabrikam”,Product[Unit Price]> Product[Unit Cost]3))06.1 理解FILTER - 图2查询筛选出了单价是单位成本的三倍以上的Fabrikam 产品此类查询会将这两个条件应用于产品表的所有行。如果两个条件中有一个更快、更有约束性,则可以在内层的FILTER函数里首先应用它。例如,以下查询将对单位价格和单位成本的筛选应用于最内层的FILTER函数,然后按品牌筛选满足价格条件的产品。EVALUATEFILTER(FILTER(Product,Product[Unit Price]> Product[Unit Cost]3),Product[Brand]=”Fabrikam”)如果反转条件,那么也会反转它们的执行顺序。以下查询仅将价格筛选应用于 Fabrikam 品牌的产品:EVALUATEFILTER(FILTER(Product,Product[Brand]=”Fabrikam”),Product[Unit Price]> Product[Unit Cost]3)当你优化DAX表达式时,这些知识会很有用。你可以选择执行顺序,首先应用最具约束性的筛选器。然而,请在彻底清楚计值上下文之后再开始优化DAX语言。你将在DAX优化章节中找到关于查询优化的更完整的介绍。这些示例的目的是让你了解表函数在嵌套调用时的执行顺序。随着DAX版本的更新,引擎的自动优化能力也在不断增强,在普通场景中,以上不同写法的实际性能差异已经微乎其微。但这种优化思路仍然有其参考价值,因为在更加复杂的模型和公式中,你无法完全依赖于引擎的自动优化。### 关于执行顺序 通常,嵌套函数的执行顺序是从最内层函数到最外层函数。稍后你将看到,CALCULATE和CALCULATETABLE可能是此行为的一个例外,因为用于计算它们的参数有特定顺序。考虑到你可能在某些相似情况下使用FILTER和CALCULATETABLE,所以在嵌套调用时要注意这个区别。## 测试题 你已经了解在FILTER中执行多个条件判断时的最优策略,让我们来回顾一下多条件下FILTER所有可能的写法。以两个条件为例,使用Contoso样例数据库文件,定义以下三个公式:A:一个FILTER合并所有条件CALCULATE(COUNTROWS(Sales),FILTER(ALL(Sales),Sales[Order Date]<=DATE(2007,1,1)&& Sales[Delivery Date]>=DATE(2006,1,1)))B:多个FILTER嵌套CALCULATE(COUNTROWS(Sales),FILTER(FILTER(ALL(Sales), Sales[Order Date]<=DATE(2007,1,1)),Sales[Delivery Date]>=DATE(2006,1,1)))C:多个FILTER并列CALCULATE(COUNTROWS(Sales),FILTER(ALL(Sales),[Order Date]<=DATE(2007,1,1)),FILTER(ALL(Sales),[Delivery Date]>=DATE(2006,1,1)))它们的用时排序是怎么样的? 06.1 理解FILTER - 图3在1250万行的Sales表上实测,AB两种写法的计算时间几乎相同,C的写法性能稍慢,但多次测试的差距平均只有几毫秒,在本例中可以忽略不计。但需要再次提醒的是,简单的公式,引擎可以较好的优化公式性能,在更加复杂的模型和公式中,性能优化仍然需要依赖你对原理的理解。为什么公式C的用时最长,这是因为当不同的筛选条件在CALCULATE并列使用时,这些筛选器参数可能会生成所有元素组合的临时笛卡尔积,所以应尽量避免使用这种写法,详细解释请参考理解CALCULATE一文的多条件并列部分。参考阅读:CALCULATETABLE vs FILTER最新最旧得票最多06.1 理解FILTER - 图4成员136*6402Follow this user#647A例中我理解的是filter对sales表的全部内容迭代筛选,保留满足条件的行,然后calculate以filter的结果赋予calculate第一参数中的sales表,最后计算表行数.我表达应该不准确,其中可能还会有很多其他数据流动,只是想问问浅层这么理解的话有问题吗?赞0踩  回复12 天 之前06.1 理解FILTER - 图5作者高飞Follow this user#650是这样的 06.1 理解FILTER - 图6赞0踩 回复11 天 之前