CALCULATE 的另一项功能是在表达式求值期间激活关系。事实上,正如你已经知道的,数据模型可能同时包含活动关系和非活动关系。你很可能会遇到非活动关系的情况,因为当两个表之间有许多关系时,只允许存在一个活动关系。
语法
USERELATIONSHIP ( <ColumnName1>, <ColumnName2> )
USERELATIONSHIP 不返回任何值;该函数只在计算期间启用指定的关系,使用时不区分两个列参数的前后顺序。
在 USERELATIONSHIP 中,关系的状态并不重要;也就是说,关系是否活动并不影响函数的使用。即使关系是不活动的,它也会被启用,并覆盖可能出现在模型中但没有在函数参数中提到的任何其他活动关系。
对于嵌套的 CALCULATE 表达式,并且存在不止一个 CALCULATE 调用 USERELATIONSHIP 函数的情况下,那么最内层的 USERELATIONSHIP 在出现冲突或歧义将覆盖外层的的同类函数。
USERELATIONSHIP 不能引用设置行级别安全性的表。
应用案例
例如,销售表的每笔订单都存储了订单日期和交货日期。通常,你希望根据订单日期进行销售分析,但对于某些特定度量值,你希望考虑交付日期。在这种情况下,你可以在销售表和 Date 表之间创建两个关系:一个基于 OrderDateKey,另一个基于 DeliveryDateKey。一次只能激活其中一个,因为你通常根据订单日期分析销售情况,所以你保持与 OrderDateKey 的关系处于活动状态,而另一个则处于不活动状态。然后,你需要创建一个基于给定日期统计交付数据的度量值,以便与订单数据进行比较。这个新度量值(交付数量)应该使用非活动关系来计算销售额,同时断开与订单日期的关系。
要解决这个问题,可以借助 CALCULATE 和 USERELATIONSHIP,代码如下所示
[Delivered Amount] := CALCULATE ( [Sales Amount], USERELATIONSHIP ( Sales[DeliveryDateKey], Date[DateKey] ) )
DeliveryDateKey 和 DateKey 之间的关系将在[Delivered Amount]计算时被激活,同时与 OrderDateKey 的关系将被停用。下图你可以看到一个数据透视表,它显示了基于 OrderDateKey 计算的销售额和基于 DeliveryDateKey 计算的销售额之间的不同。
当使用 USERELATIONSHIP 激活关系时,你需要注意一个非常重要的现象:关系的定义发生在调用表的时候,而不是在调用 RELATED 或其他关系函数的时候。
例如,如果你想计算 2007 年交付的产品数量,这个公式将不起作用:
[Delivered Amount in 2007_wrong] := CALCULATE ( [Sales Amount], FILTER ( Sales, CALCULATE ( RELATED ( Date[CalendarYear] ), USERELATIONSHIP ( Sales[DeliveryDateKey], Date[DateKey] ) ) = 2007 ) )
原因在于 FILTER 迭代销售表(发生对销售表的调用),然后计值条件表达式。在计值期间,它更改了活动关系,然后调用 RELATED。但是,销售表和日期表之间的关系是在调用 FILTER 时定义的,而不是在使用 RELATED 的时候。另外,CALCULATE 内部也不存在可供调用的行上下文。
如果你想执行一个类似上面的计算,需要用以下方式重写这个度量值:
[Delivered Amount in 2007_still wrong] := CALCULATE ( [Sales Amount], FILTER ( CALCULATETABLE ( Sales, USERELATIONSHIP ( Sales[DeliveryDateKey], Date[DateKey] ) ), RELATED ( Date[Calendar Year] ) = 2007 ) )
在后一个公式中,销售表是在 CALCULATETABLE 激活所需的关系之后调用的。因此,FILTER 内部对 RELATED 的调用也发生在 DeliveryDateKey 关系被激活的情况下。
这种行为使得在计算列中使用非默认关系成为一种复杂的操作,因为计算列中已经隐含了对表的调用,你无法控制它,也无法使用 CALCULATE 和 USERELATIONSHIP 更改该行为*。
正确写法:
[Delivered Amount in 2007_right] := CALCULATE ( [Sales Amount], USERELATIONSHIP ( Sales[DeliveryDateKey]; 'Date'[DateKey] ), 'Date'[Calendar Year] = 2007 )
深入理解 USERELATIONSHIP
未完待续
原因在于 FILTER 迭代销售表(发生对销售表的调用),然后计值条件表达式。在计值期间,它更改了活动关系,然后调用 RELATED。但是,销售表和日期表之间的关系是在调用 FILTER 时定义的,而不是在使用 RELATED 的时候。另外,CALCULATE 内部也不存在可供调用的行上下文。
原版书中是However, the relationship between Sales and Date has been defined when Sales was invoked, not when RELATED is used.
这种行为使得在计算列中使用非默认关系成为一种复杂的操作,因为计算列中已经隐含了对表的调用,你无法控制它,也无法使用 CALCULATE 和 USERELATIONSHIP 更改该行为*
———————————————————————————————————————————-
高老师: 我在Date 表里面建立了新建列, 使用CALCULATE+USERELATIONSHIP 激活了Delivery date 和date 的关系. 是不是和上面的描述冲突了呢?
老师你好
[Delivered Amount in 2007_wrong] :=
CALCULATE (
[Sales Amount],
FILTER (
Sales,
CALCULATE (
RELATED ( Date[CalendarYear] ),
USERELATIONSHIP ( Sales[DeliveryDateKey], Date[DateKey] )
) = 2007
)
)
这里的RELATED ( Date[CalendarYear] )是不是错的?CAL中没有行上下文,而RELATED需要行上下文
你好老师,”FILTER 使用默认的关系,不考虑 CALCULATETABLE 对活动关系的修改“,这是FILTER的特性吗?但在之前的章节中都没有提及过,意思是FILTER的第一个参数如果出现了物理表,则只会使用它的默认关系吗?
老师,最后那个正确写法还有点不理解。userelationship改变的是calculate内部第一参数的计值上下文吧,但筛选器’Date'[Calendar Year] = 2007 不是在calculate外部计值上下文中计算吗,应该没有被userelationship作用啊。
[Delivered Amount in 2007_still wrong] 这个度量值里,filter使用的是默认关系,而calculateable使用被激活后关系,内层关系能覆盖外层关系吗?不能覆盖的话,因两个关系都存在,所以度量结果是错误的吗?谢谢老师解答。
高老师,Userelationship函数,套在Calculate里,不会随着度量值传递。但是,使用时间智能函数时,却是会传递的。这是啥原因是?
咦 第一个图挂了