0%

INTERSECT & EXCEPT

其实这篇文章,这样发出来,是不太好的。
因为INTERSECT、EXCEPT不是两个和其他函数毫无关联的函数,这两个函数如果想要讲清楚,涉及到的其他的一些函数,例如TREATAS函数也要一起讲。
但是,我依然发出来了,因为我仔细想过,我写的任何东西,其实主要是给我自己看的,把我认为有价值的东西写出来,如同写笔记,所以就不需要考虑太多其他的。


前言

在很多 Business Analysis 计算中,会需要对两列进行 Left Join 或者 Inner Join 等 Join方法。

下图是 SQL 的 Join 查询示意图,可以作为参考。当然 DAX 中并没有这么多函数,例如据我所知 DAX 并没有 Right Join 对应的函数。

应用场景

前面说到 Business Analysis 中会遇到 Left Join 或者 Inner Join ( 我个人的经验是 Inner Join的使用场景更多一些 ),下面举两个例子。

例如:

  1. 我们在做 Basket Analysis 的时候,需要知道相同筛选上下文之下,同时购买了指定的两个 SKU 的 Customer 有哪些。
  2. 我们在做 Customer Sales Trend 分析的时候,需要知道 2021 年处于头部客户 List 中的 Customer 有多少在 2022 年跌入尾部 List。

对于这些分析场景,我们都需要对于同一个表中的同一列做两次筛选,并对筛选的结果 List 进行 Inner Join,对应的 DAX 函数是 INTERSECT

INTERSECT & EXCEPT

在介绍 INTERSECT 之前首先需要说明,其实现在对于同样的需求,我们大部分时候使用 TREATAS 函数,只有当 TREATAS不可用时,才会使用INTERSECT 函数。原因是 TREATAS 运行效率更高一些,这一点在优化代码的时候可以考虑。

INTERSECT ( <LeftTable>, <RightTable> )

可以看到 INTERSECT 包含两个参数, Left Table 和 Right Table,而 INTERSECT 运算的结果其实和下图 INNER JOIN的结果相同,都是取 Left Table 和 Right Table 的交集。

image-20220920113830617

EXCEPT  ( <LeftTable>, <RightTable> )

可以看到 EXCEPT 同样包含两个参数, Left Table 和 Right Table,而 EXCEPT 运算的结果其实和下图 Left Anti 的结果相同。

image-20220920115901454

在实际应用中,举例如下:

C80_C20_2020 = 

// 2020年属于Pareto 前 80% 的客户列表。
VAR Cust80_2020 =
    CALCULATETABLE(
        SUMMARIZE(
            'ECDatas SSDTotal',
            'ECDatas SSDTotal'[Customer]
        ),
        FILTER(
            VALUES( 'ECDatas SSDTotal'[Customer] ),
            [Pareto% _Cust_NSV] <= 0.8
        ),
        Calendar[Year] = 2020
    )
    
// 2021年属于Pareto 后 20% 的客户列表。
VAR Cust20_2021 =
    CALCULATETABLE(
        SUMMARIZE(
            'ECDatas SSDTotal',
            'ECDatas SSDTotal'[Customer]
        ),
        FILTER(
            VALUES( 'ECDatas SSDTotal'[Customer] ),
            [Pareto% _Cust_NSV] > 0.8
        ),
        Calendar[Year] = 2021
    )

RETURN
    CALCULATE(
        [SumNetValue],
        //求交集之后的 Customer List 再和总表中的 Customer 列进行 TREATAS,相当于求交集。
        TREATAS(
        	// 对2020年 前80%的客户和 2021年 后20%的客户求交集
            INTERSECT( Cust80_2020, Cust20_2021 ),
            'ECDatas SSDTotal'[Customer]
        ), Calendar[Year] = 2020
    )

上面代码中可以看到,RETURN 中,利用 INTERSECT 对 VAR 的两个表,进行 Inner Join,也就是求交集。

当然,在这里,我本身也有些学艺不精,还有一些需要测试的内容,需要测试的内容主要是 Left Table 的沿袭问题。

本篇中,不会专门对于 EXCEPT 进行举例,因为 EXCEPT 其实和 INTERSECT 的用法基本相同,只是结果完全不同而已。