美文网首页
DAX高级:用作CALCULATE筛选器的日期字段

DAX高级:用作CALCULATE筛选器的日期字段

作者: PowerBI战友联盟 | 来源:发表于2017-11-18 20:15 被阅读1543次

    问题背景

    本问题来自我的课程:《Power BI 自动化用户运营分析》 中的学生提问。

    课程中给出了多种进行新用户数相关的计算方法,发现一个问题:

    上图给出了 和日期有关的DAX使用 在不同算法(不妨依次称为1,2,3,4)中的实现。

    不必深究算法,这里想强调的是,前两种算法或使用ALL(日期表),或使用FILTER(ALL(日期表))的方式忽略了日期表的影响。而在算法3,4中会发现,即使去掉ALL(日期表),计算依然是正确的,这是为什么?

    等价问题

    当你觉得问题复杂时,找到最小核心点,分而治之。

    解决上述的问题的最佳方式不是去解决它,而是观察,测试去发现问题的范围,进而找到等价的问题,并去研究等价问题。

    建立等价问题

    如果觉得上述背景复杂,那我们将问题做等价简化,有A,B两个表且满足下面的关系:

    A,B的数据以及度量值如下:

    A表:

    B表:

    度量值:

    related count in B = 
    VAR current_id = MIN( A[id] )
    RETURN CALCULATE( COUNTROWS( B ) , A[id]< current_id  )
    

    诡异的结果

    解释:由于计算上下文(本处是筛选上下文)的存在,在第2行中,CALCULATE中存在筛选器A[item]="b",此时在CALCULATE中出现的筛选A[id] < current_id,按照CALCULATE的执行原则,因为这是两个不同的字段,因此他们将共同起作用,而显而易见的是,他们共同的作用下,对表A的筛选应该是空集,而实际却并非如此。

    破解诡异

    将A表[id]字段的数据类型改为INTEGER,看看效果。 如下:

    正如刚刚分析的,这才是应该呈现的效果。问题来了:为什么改成INTEGER类型就正确了,符合我们对CALCULATE运算逻辑的理解:筛选上下文是当前的A[item]而CALCULATE内部添加了筛选器A[id] < current_id,它们共同的作用的确应该为空。

    探究DAX引擎的实际工作

    我们最后给出的任何答案,如果想确保正确,那一定是看到了DAX引擎的实际执行,为了解决这个谜题,我们设计了4次对比。

    首先,我们猜测这是与取消筛选有关的,可能会涉及到ALL,于是我们的度量值可以是两种:

    第一种

    related count in B = 
    VAR current_id = MIN( A[id] )
    RETURN CALCULATE( COUNTROWS( B ) , A[id]< current_id  )
    

    第二种

    related count in B = 
    VAR current_id = MIN( A[id] )
    RETURN CALCULATE( COUNTROWS( B ) , A[id]< current_id , ALL(A) )
    

    注意在第二种度量值中使用了ALL(A)

    对比试验设计

    试验 内容
    试验 1 数据类型:integer;度量值:不加ALL版本
    试验 2 数据类型:date;度量值:不加ALL版本
    试验 3 数据类型:integer;度量值:加ALL版本
    试验 4 数据类型:date;度量值:加ALL版本

    DAX Studio查看物理查询

    如果说要理解程序运作的CPU逻辑是查看汇编或二进制代码的话,那么理解DAX执行的最底层逻辑就是查看DAX引擎执行的物理查询。(而不是逻辑查询)

    按照试验的对比设计,以及常规的想法,我们应该预期试验1和试验2除了在数据类型上不同,其他应该都一致;试验2和试验4因为有ALL的加入或不加入,应该有较大差别;诸如此类。

    在DAX Studio中,按照这个方式来运行:

    限于篇幅,不再给出每个试验的物理查询文本,但将运行好的物理查询文本拷贝出来进行对比,我们对不同试验,得到以下对比结果:

    试验 物理查询行数 related count in B 结果
    试验 1 integer 不加ALL 23
    试验 2 date 不加ALL 40 非空
    试验 3 integer 加ALL 40 非空
    试验 4 date 加ALL 40 非空

    可以逐个将四个试验的文本依次详细对比:

    试验 1 对比 试验 2

    对比显示:

    • 不仅在数据类型处有区别
    • 试验2足足比试验1多出了更多的物理查询内容

    虽然DAX表达式完全一样,仅仅是数据类型的不同,物理查询居然相差这么大。

    试验 2 对比 试验 3

    对比显示:仅在数据类型处有区别。
    DAX表达式有ALL(A)的明显不同,而物理查询却仅仅是数据类型的不同。

    试验 3 对比 试验 4

    对比显示:仅在数据类型处有区别。
    DAX表达式有ALL(A)的明显不同,而物理查询却仅仅是数据类型的不同。

    试验 2 对比 试验 4

    对比显示:物理查询完全一样。
    DAX表达式有ALL(A)的明显不同,而物理查询却完全一致。

    水落石出

    通过4个试验以及4组试验对比,我们完全确认: 试验 2 date 不加ALL版本的度量值中,DAX引擎在计算时实际自动添加了ALL(A)。

    总结

    结合更多试验,将发现以下重要事实:若CALCULATE的筛选器中存在某表的日期字段,如:A[date],且该字段恰为主键并已与其他表建立关系,DAX引擎将在此CALCULATE的筛选器中自动加入ALL(A)。

    值得特别注意的是:

    • 该表不一定是日期表,只要该字段是日期字段即可。
    • 一定是该字段已经作为主键并与其他表建立了关系。

    由此,原问题得到了完整的解答。

    补充

    什么是主键
    如果从A[C1]上连接一条线出来,连到B[C1]身上,则A[C1]叫做主键。也就是连线出发的字段。

    为什么会有这么诡异的问题
    这是Power BI Desktop为了实现时间智能函数而设计的内部机制。例如:
    CALCULATE( [销售额] , DATEADD( 日期表[日期] , 1 , MONTH ) ) 将在该机制下,不需要考虑加入ALL(日期表)而得以正确运行。

    更多参考:

    相关文章

      网友评论

          本文标题:DAX高级:用作CALCULATE筛选器的日期字段

          本文链接:https://www.haomeiwen.com/subject/inqyvxtx.html