从数据到信息
从信息到洞察

理解 USERELATIONSHIP

CALCULATE 的另一项功能是在表达式求值期间激活关系。事实上,正如你已经知道的,数据模型可能同时包含活动关系和非活动关系。你很可能会遇到非活动关系的情况,因为当两个表之间有许多关系时,只允许存在一个活动关系。

示意:活动关系(实线)和非活动关系(虚线)

语法

USERELATIONSHIP ( <ColumnName1>, <ColumnName2> )

USERELATIONSHIP 不返回任何值;该函数只在计算期间启用指定的关系,使用时不区分两个列参数的前后顺序。

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 更改该行为*

实际上,在 DAX 权威指南第一版中,最后这个重写的度量值仍然是错误的,原因在于虽然 FILTER 的结果使用了修改后的关系,但是外层的 CALCULATE 的初始环境仍然使用了默认的关系,这使得最终结果返回空值。这里保留了公式,仅作为错误示范

正确写法:

[Delivered Amount in 2007_right] := 
CALCULATE (
    [Sales Amount],
    USERELATIONSHIP ( Sales[DeliveryDateKey], 'Date'[DateKey] ),
    'Date'[Calendar Year] = 2007
)

深入理解 USERELATIONSHIP

未完待续

 

51
说点什么

1000
 
鼓掌微笑开心憧憬爱你色并不觉得吃瓜doge二哈喵喵思考笑哭捂脸悲伤大哭抓狂汗偷笑打脸捂眼黑线问号晕拜拜闭嘴衰咒骂ok作揖
15 评论数
36 被回复的评论
16 订阅评论的人数
 
查看最近回复
查看最热评论
  订阅本文评论  
最新 最旧 得票最多
提醒
成员
似水无痕

老师,一个很奇怪的现象。
模型用的是第2版书上的模型, 日历表和销售表活动关系是 ‘日历表'[日期] 和 ‘销售表'[订单日期] , 非活动关系是 ‘日历表'[日期] 和 ‘销售表'[交付日期]
如图所示,当将非活动关系使用USERELATIONSHIP激活时,为什么交叉筛选不论用 ‘销售表'[订单日期] 还是用 ‘销售表'[交付日期] ,得到的结果居然相同!这是什么原因?
我一直以为 “第1个CROSS订单日期”会返回日历表的所有日期

02.png
01.png
成员
状态的状

“虽然 FILTER 的结果使用了修改后的关系,但是外层的 CALCULATE 的初始环境仍然使用了默认的关系,这使得最终结果返回空值”

请问老师,为什么会返回空值哈?FILTER 返回的也是一个表,内外关系不一致,我可以理解会导致筛选结果不准确。但是无论用哪个关系,筛选的应该[date]这个列,必定会返回空值吗?

成员
hellolsdp

老师您好,如果我想用userelationship为related激活非默认关系,我在计算列写calculate(related,userelationship())的时候,calculate会把计算列的行上下文转化成筛选上下文,导致related失效。正确的应该怎么写呢?

游客
Major

老师好,由于USERELATIONSHIP只能用于calculate中去激活关系。现在有两个表,有两条关系(活动&非活动),我想通过其中维度表筛选另一张数据表。在这种情况下,如何激活非活动状态的关系,从而使得交叉筛选得以实现?谢谢老师。

成员
153****1882

高老师,在still wrong的度量值里,麻烦您拓展解释下“原因在于虽然 FILTER 的结果使用了修改后的关系,但是外层的 CALCULATE 的初始环境仍然使用了默认的关系,这使得最终结果返回空值”。具体是如何产生冲突的?另外看您之前给别人的回复,为什么只有当订单日期和交付日期相同时才会有值?谢谢!

游客
839838408

老师好,在文中,您提到:“关系的定义发生在调用表的时候,而不是在调用 RELATED 或其他关系函数的时候。”
请问在如下度量值中,并没有调用表,那么关系的定义发生在什么时候呢?
[Delivered Amount] :=
CALCULATE (
[Sales Amount],
USERELATIONSHIP ( Sales[DeliveryDateKey], Date[DateKey] )
)

游客
竹子小Shou

Delivered Amount 2007 _right =
CALCULATE (
CALCULATE(
[Sales Amount],
FILTER(
Sales,
RELATED(‘Date'[Calendar Year]) = “CY 2007”
)
),
USERELATIONSHIP ( Sales[Delivery Date], ‘Date'[Date] )
)

Delivered Amount 2007 _wrong =
CALCULATE (
[Sales Amount],
FILTER(
Sales,
RELATED(‘Date'[Calendar Year]) = “CY 2007”
),
USERELATIONSHIP ( Sales[Delivery Date], ‘Date'[Date] )
)

老师你好,我想知道为什么Delivered Amount 2007 _wrong为什么返回不出结果,它和Delivered Amount 2007 _right的区别仅仅是中间少了一层CALCULATE

成员
ArcSaber

原因在于 FILTER 迭代销售表(发生对销售表的调用),然后计值条件表达式。在计值期间,它更改了活动关系,然后调用 RELATED。但是,销售表和日期表之间的关系是在调用 FILTER 时定义的,而不是在使用 RELATED 的时候。另外,CALCULATE 内部也不存在可供调用的行上下文。

原版书中是However, the relationship between Sales and Date has been defined when Sales was invoked, not when RELATED is used.

成员
Jack S

这种行为使得在计算列中使用非默认关系成为一种复杂的操作,因为计算列中已经隐含了对表的调用,你无法控制它,也无法使用 CALCULATE 和 USERELATIONSHIP 更改该行为*
———————————————————————————————————————————-
高老师: 我在Date 表里面建立了新建列, 使用CALCULATE+USERELATIONSHIP 激活了Delivery date 和date 的关系. 是不是和上面的描述冲突了呢?

屏幕截图 2020-10-31 123302.png
成员
CatCatLa

老师你好
[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需要行上下文

游客
JohnZcat

你好老师,”FILTER 使用默认的关系,不考虑 CALCULATETABLE 对活动关系的修改“,这是FILTER的特性吗?但在之前的章节中都没有提及过,意思是FILTER的第一个参数如果出现了物理表,则只会使用它的默认关系吗?

成员
嘿乎乎

老师,最后那个正确写法还有点不理解。userelationship改变的是calculate内部第一参数的计值上下文吧,但筛选器’Date'[Calendar Year] = 2007 不是在calculate外部计值上下文中计算吗,应该没有被userelationship作用啊。

成员
139****3194

[Delivered Amount in 2007_still wrong] 这个度量值里,filter使用的是默认关系,而calculateable使用被激活后关系,内层关系能覆盖外层关系吗?不能覆盖的话,因两个关系都存在,所以度量结果是错误的吗?谢谢老师解答。

成员
bbzhdlp

高老师,Userelationship函数,套在Calculate里,不会随着度量值传递。但是,使用时间智能函数时,却是会传递的。这是啥原因是?

游客
飞飞飞

咦 第一个图挂了

DAX 圣经

导读

初识 DAX

DAX 基础知识

DAX 原理

DAX 高级原理

基础函数类型

迭代函数

CALCULATE 函数

CALCULATE 调节器

基础表函数

条件判断函数

查找匹配函数

时间智能函数

统计类函数

投影函数

分组/连接函数

集合函数

其他函数