裸SUM
和包裹在CALCULATE
中的总和有什么区别?
Measure1 = SUM( tab[col1]) )
Measure2 = CALCULATE ( SUM( tab[col1]) ) )
更新。
我给了另一个answer问题,它使用包装的计算。问题的作者对此做了解释,但我仍然不明白。这是作者建议的措施:
Expected Result =
SUMX (
VALUES ( Unique_Manager[Manager] ),
VAR SumBrand = CALCULATE ( SUM ( Budget_Brand[BudgetBrand] ) )
VAR SumProduct = CALCULATE ( SUM ( Budget_Product[BudgetProduct] ) )
RETURN
IF ( ISBLANK ( SumProduct ), SumBrand, SumProduct )
)
解释:
(...)请注意,我将总和打包在CALCULATE中。这样做是为了 从SUMX内部的行上下文执行上下文转换( 特定的Manager),以将该Manager作为过滤器上下文 BudgetBrand和BudgetProduct。将这些总和存储为变量使得 对于更易读的IF行,仅要求计算SumProduct 一次而不是两次。
我知道什么是过滤器上下文。但是我不明白什么是上下文过渡。还有其他转换吗?
答案 0 :(得分:3)
在行上下文中使用CALCULATE
时,将发生过渡,其中每一行成为过滤器,并使用该行的所有列作为过滤器为每一行扫描整个表。如果表重复,这将影响性能,并且还可能导致意外结果。
您提供的两个版本可能返回相同的值。但是,如果不这样做,可能是因为表中的行重复。
您可能会发现this article非常有用。
答案 1 :(得分:2)
此答案通常解决CALCULATE
的使用问题,并涉及过滤器上下文,行上下文和上下文转换的主题。
根据原始问题的定义,根据下面的原始响应,[Measure1]和[Measure2]的行为相同。有关对CALCULATE
的更详细说明,请参见对此答案的修改。
通常,如果要在行上下文中查看表达式,则将CALCULATE
与单个参数一起使用以引起上下文转换(行上下文->过滤上下文)。
我看到的一个常见的初学者错误是表达式中的多余/不必要的CALCULATE
。 CALCULATE
仅在要影响第一个参数的过滤器上下文时才应使用。这有两种一般形式:
两者可能会聚在一起。
以上所述的推论是,除非调用站点位于行上下文中,否则切勿将CALCULATE
与一个arg一起使用。
修改:基于评论和更新的问题
这个问题似乎有些混乱。因此,在进入上下文转换之前,我将首先进行清理。
注意:无论我在下面提到的CALCULATE
还是什么,您都可以阅读CALCULATETABLE
,其行为几乎相同。第一个用于标量表达式,第二个用于表表达式。
度量不是仅仅是命名的DAX表达式。量度是一个命名的DAX表达式,其周围有一个隐含的CALCULATE
。因此,如果要用量度表达式替换对量度的引用,则不只是做简单的文本替换,还可以编写CALCULATE ( <measure body> )
。
如果要询问的形式是自洽的,我尽量不要猜测一个问题的不同含义。我相信你想问:
以下DAX表达式之间有什么区别?
SUM ( 'tab'[col1] )
和
CALCULATE ( SUM ( 'tab'[col1] ) )
这与您提出的问题本质上不同,因为您要询问的是两个完全定义的度量,而不是两个DAX代码段。这些措施的行为相同,因为它们的扩展在逻辑上是等效的:
//Measure 1 definition:
Measure1 = SUM ( 'tab'[col1] )
// Measure 1 expands to the following, and you would use this if you were
// replacing a reference with code:
//Expansion1:
CALCULATE ( SUM ( 'tab'[col1] ) )
//Measure2 definition and expansion:
Measure2 = CALCULATE ( SUM ( 'tab'[col1] ) )
//Expansion2:
CALCULATE ( CALCULATE ( SUM ( 'tab'[col1] ) ) )
因此,您的度量在语义上(尽管不是文本上)是相同的。两者都以包裹在SUM
中的CALCULATE
的形式执行。 [Measure2]刚好在扩展时有一个额外的CALCULATE
。
那么CALCULATE
的作用是什么?很多。作为参考,当我进行DAX培训时,CALCULATE
以及过滤器和行上下文是一个数小时的时段。
CALCULATE
执行以下操作。
执行上下文转换。它创建一个新的过滤器上下文,在其中可以评估其第一个参数表达式。这个新的过滤器上下文包括以下内容(合并为一个过滤器上下文):
a。 CALCULATE
b。 CALCULATE
计算参数2-N(称为setfilters)以修改(添加,删除或修改现有的)步骤(1)中的过滤器上下文,最后
在由步骤(1)和(2)确定的新过滤器上下文中评估arg1中的表达式。
所以,这有几个问题,即:
因此,首先,过滤上下文。筛选器上下文来自多个DAX函数,包括CALCULATE
,CALCULATETABLE
,SUMMARIZE
,SUMMARIZECOLUMNS
和GROUPBY
。此列表并非旨在详尽无遗,但确实涵盖了一些非常常见的功能。
只要您在报表工具中与表格模型互动,例如Excel数据透视表或Power BI报表,您在GUI中的操作会生成查询,这些查询可用于填充任何可视化对象。从这些(和其他)报告工具的角度来看,过滤器上下文来自:
您可以将过滤器上下文视为一组“表” [Column]->值映射。无论选择什么文字值或满足选择条件的文字值,都会成为过滤器上下文。
例如,让我们考虑一个矩阵视觉,在行上具有“日历” [Year],在列上具有“ Calendar” [MonthName],“ Product” [Category] =“ Clothing”的切片器以及页面级过滤器为“日历” [年份]> 2015。我们将查看在第三行第四列的矩阵中评估的度量[M]的过滤器上下文(2018年4月)
Filter Context:
'Calendar'[Year]=2018
'Calendar'[Year]>2015
=> 'Calendar'[Year] IN {2016, 2017, 2018, ..., N} // for whatever years exist in the calendar
'Calendar'[Month]="April"
'Product'[Category]="Clothing"
基于年和月的交集,矩阵的每个单元格都有其自己的过滤器上下文,但其余部分将保持不变。对于底部的总计行,过滤器上下文将没有来自矩阵的特定年份,但仍会受到页面级过滤器的影响。对于右侧的总计列,将没有月份的上下文,但是会有特定的年份。对于矩阵右下角的Grant total单元格,唯一的过滤器为:
'Product'[Category]="Clothing"
'Calendar'[Year]>2015 //from the page-level
总而言之,过滤器上下文与您可能理解的内容非常一致。我发现对于大多数人来说,单独过滤上下文是有道理的。
现在用于行上下文。每当我们迭代一个表时,就存在行上下文。您会在两个地方找到行上下文:
SUMX
,AVERAGEX
等...)FILTER
ADDCOLUMNS
每当我们谈论行上下文时,我们都在谈论迭代。您可以想到一个for循环,例如:
//pseudocode
for row in table:
<expression>
您可能还认为行上下文类似于SQL游标,它会迭代表的行。它在很大程度上等效于快进只读游标。
我们一次考虑一行。行上下文由要迭代的表的列中的一组文字值组成。
因此,给定一个具有列(Id,金额,日期)的表“ T”,SUMX ( 'T', <expression )
中的行上下文由特定值“ T” [Id],“ T” [Amount]组成和'T'[Date]。您可以通过<expression>
中的列引用来引用这些值中的任何一个。您还可以将表值函数用作迭代器的第一个参数,例如SUMX ( VALUES ( 'T'[Date] ), <expression> )
。在这种情况下,我们迭代的表是VALUES ( 'T'[Date] )
的返回,它是'T'[Date]列中唯一值的集合。在这种情况下,行上下文仅包含来自“ T” [Date]的值-其余的“ T”不在行上下文中。
注意:当我们在行上下文中时,我们可以按名称引用一列而无需对其进行汇总-这在DAX中除行上下文外其他任何地方都无效。
注2:基本的聚合函数(例如SUM
或COUNTROWS
与行上下文没有交互)。因此,对于下面的表和表达式,我们将看到可能没有意义的结果:
//Table, 'T' with schema as above
{
(1, 10, 2019-02-01),
(2, 20, 2019-02-01),
(3, 30, 2019-03-01),
(4, 40, 2019-03-02)
}
//Add calculated column to 'T'
C = SUM ( 'T'[Amount] )
// Result would be 100 on every row - the total of 'T'[Amount]
//Measure on a card visual with no other filters:
M = SUMX ( 'T', SUM ( 'T'[Amount] ) )
// Result would be 400, which is the sum of 'T'[Amount] calculated once per row
// and summed together
//M2 on card with no other filters
M2 = SUMX ( VALUES ( 'T'[Date] ), SUM ( 'T'[Amount] ) )
// Result is 300, which is the sum of 'T'[Amount] calculated once per unique date
// and summed together
当我们在行上下文中并且希望该行上的值有助于过滤上下文时,可以将聚合包装在CALCULATE
中,以将行上下文转换为过滤上下文。这称为上下文转换。
// Same table as above:
M3 = SUMX ( VALUES ( 'T'[Date] ), CALCULATE ( SUM ( 'T'[Amount] ) ) )
// result on card would be 100, the actual total
我们可以将计算分解为以下迭代:
// Input table would be {2019-03-02, 2019-02-01, 2019-03-01}
//Iteration1:
1. Row context: 'T'[Date]=2019-03-02
2. CALCULATE transitions 'T'[Date] value to Filter context: 'T'[Date]=2019-03-02
3. SUM is evaluated in filter context from step (2)
4. Result of iteration1 = 40
//Iteration2:
1. Row context: 'T'[Date]=2019-02-01
2. CALCULATE transitions 'T'[Date] value to Filter context: 'T'[Date]=2019-02-01
3. SUM is evaluated in filter context from step (2)
4. Result of iteration1 = 30 //note both [Amount]s for 2019-02-01 contribute to this
//Iteration3:
1. Row context: 'T'[Date]=2019-03-01
2. CALCULATE transitions 'T'[Date] value to Filter context: 'T'[Date]=2019-03-01
3. SUM is evaluated in filter context from step (2)
4. Result of iteration1 = 30
// Final result - combine iteration results with sum:
40 + 30 + 30 = 100
请注意,过滤器上下文会自动导航模型中的关系。行上下文仅由要迭代的表中的值组成。如果需要在行上下文中导航关系,则可以使用RELATED
或RELATEDTABLE
,也可以使用CALCULATE
或CALCULATETABLE
将行上下文转换为过滤器上下文。
因此,在您的链接示例中:
Expected Result =
SUMX (
VALUES ( Unique_Manager[Manager] ),
VAR SumBrand = CALCULATE ( SUM ( Budget_Brand[BudgetBrand] ) )
VAR SumProduct = CALCULATE ( SUM ( Budget_Product[BudgetProduct] ) )
RETURN
IF ( ISBLANK ( SumProduct ), SumBrand, SumProduct )
)
SumBrand
是当前行上下文中“ Unique_Manager” [Manager]的“ Budget_Brand” [BudgetBrand]的总和,即,管理器是迭代中当前行的值。同样,SumProduct
是行上下文中管理器的'Budget_Product'[BudgetProduct]的总和。
您可以轻松定义以下内容:
Brand Budget = SUM ( 'Budget_Brand'[BudgetBrand] )
Product Budget = SUM ( 'Budget_Product'[BudgetProduct] )
Expected Result =
SUMX (
VALUES ( 'Unique_Manager'[Manager] ),
VAR SumBrand = [Brand Budget]
VAR SumProduct = [Product Budget]
RETURN
IF ( ISBLANK ( SumProduct ), SumBrand, SumProduct )
)
我可能会进行如下重构,以便仅在需要时才计算品牌预算:
Expected Result =
SUMX (
VALUES ( 'Unique_Manager'[Manager] ),
VAR SumProduct = [Product Budget]
RETURN
IF ( ISBLANK ( SumProduct ), [Brand Budget], SumProduct )
)
无论是否进行了重构,上述引用度量的版本在语义上与内联CALCULATE ( SUM ( ... ) )
的版本相同。
这是因为,如本编辑部分前面所述,以下两个是等效的:
Measure = SUM ( 'tab'[col1] )
CALCULATE ( SUM ( 'tab'[col1] ) )
我希望这有助于理解我为何如此勇敢地回答您的原始问题。作为度量,您的两个表达式在语义上是等效的。作为隔离表达式,它们不是。
答案 2 :(得分:2)
取决于您使用表达式的方式,即计算列vs测量值以及在什么情况下使用。过滤器上下文是从报表中的活动过滤器派生的,即SLICERS,CROSS FILTER通过可视化本身,甚至可以通过模型中存在的关系传播。在计算列中使用它们将产生非常不同的结果。见下图:
如您所见,Ive提供了一个非常基本的数据集,显示职位名称及其各自的薪水。当使用不带计算饱和度的表达式时,没有提供过滤器上下文,并且不会隐式派生任何过滤器上下文,因此该列将导致整个“薪水”字段的TOTAL总和。当我们在计算语句中包装相同的表达式时,我们将提供一个ROW CONTEXT并获取表中每个ROW的总和。两种截然不同的结果。
在某种程度上使用时,它们会产生相同的结果。见下图: 这是因为SUM()度量将隐式地用CALCULATE包裹,并继承与包含CALCULATE语句的MEASURE相同的功能。在这种情况下,树形图用作切片器,并为两个度量提供了过滤器上下文,从而产生相同的结果。
此ARTICLE在解释行和过滤器上下文方面做得很好。
希望这会有所帮助!