使用变量改进 DAX 公式

作为数据建模人员,编写和调试某些 DAX 计算可能会很困难。 复杂计算的要求通常包括编写复合表达式或复杂表达式。 复合表达式可能涉及使用多种嵌套函数,并且可能会重用表达式逻辑。

在 DAX 公式中使用变量有助于编写更复杂而高效的计算。 变量可以提高性能、可靠性和可读性,并降低复杂性。

在本文中,我们将通过使用同比 (YoY) 销售增长的示例度量值来演示前三个优势。 (YoY 销售增长公式为:现年销售额减去去年同期销售额,再除以去年同期销售额。)

让我们从下面的度量值定义开始。

Sales YoY Growth % =
DIVIDE(
    ([Sales] - CALCULATE([Sales], PARALLELPERIOD('Date'[Date], -12, MONTH))),
    CALCULATE([Sales], PARALLELPERIOD('Date'[Date], -12, MONTH))
)

该度量值将产生正确的结果,不过还是让我们看看如何对其进行改进。

提高性能

请注意,该公式重复了计算“去年同期”的表达式。 此公式效率很低,因为它要求 Power BI 计算两次相同的表达式。 使用变量 VAR 可以更高效地进行度量定义。

下面的度量值定义表示一项改进。 它使用表达式将“去年同期”结果分配给名为 SalesPriorYear 的变量 。 然后,在 RETURN 表达式中使用该变量两次。

Sales YoY Growth % =
VAR SalesPriorYear =
    CALCULATE([Sales], PARALLELPERIOD('Date'[Date], -12, MONTH))
RETURN
    DIVIDE(([Sales] - SalesPriorYear), SalesPriorYear)

该度量值将继续生成正确的结果,并在大约一半的查询时间内完成此操作。

提高可读性

在前面的度量值定义中,请注意变量名称的选择如何使 RETURN 表达式更易于理解。 该表达式简短而具有自述性。

简化调试

变量还有助于调试公式。 要测试分配给变量的表达式,可以临时重写 RETURN 表达式以输出变量。

以下度量值定义仅返回 SalesPriorYear 变量 。 请注意它注释掉预期 RETURN 表达式的方式。 通过此方法,可以在调试完成后轻松将其还原。

Sales YoY Growth % =
VAR SalesPriorYear =
    CALCULATE([Sales], PARALLELPERIOD('Date'[Date], -12, MONTH))
RETURN
    --DIVIDE(([Sales] - SalesPriorYear), SalesPriorYear)
    SalesPriorYear

降低复杂性

在较早版本的 DAX 中,尚不支持变量。 需要使用引入新筛选器上下文的复杂表达式来使用 EARLIEREARLIEST DAX 函数,以引用外部筛选器上下文。 遗憾的是,数据建模人员发现这些功能难以理解和使用。

变量始终在应用 RETURN 表达式的筛选器之外进行计算。 出于此原因,在修改后的筛选器上下文中使用变量时,实现的结果与 EARLIEST 函数相同。 因此,可以避免使用 EARLIER 或 EARLIEST 函数。 这意味着你现在可以编写较简单且更易于理解的公式。

请考虑以下添加到 Subcategory 表中的计算列定义 。 它基于 Subcategory Sales 列值评估每个产品子类别的排名 。

Subcategory Sales Rank =
COUNTROWS(
    FILTER(
        Subcategory,
        EARLIER(Subcategory[Subcategory Sales]) < Subcategory[Subcategory Sales]
    )
) + 1

EARLIER 函数用于引用当前行上下文中的 Subcategory Sales 列值 。

可以通过使用变量而不是 EARLIER 函数来改进计算的列定义。 CurrentSubcategorySales 变量将 Subcategory Sales 列值存储在当前行上下文中,并且 RETURN 表达式在修改的筛选器上下文中使用它 。

Subcategory Sales Rank =
VAR CurrentSubcategorySales = Subcategory[Subcategory Sales]
RETURN
    COUNTROWS(
        FILTER(
            Subcategory,
            CurrentSubcategorySales < Subcategory[Subcategory Sales]
        )
    ) + 1