引言
在2025年9月的版本更新中,用户定义函数(UDF)作为一项预览功能首次亮相。这项创新特性允许我们将复杂的业务逻辑封装成可重用的函数,这些函数能够像任何标准DAX函数一样被调用。本文旨在通过一个实际案例——基于通胀率进行收入预测——深入演示如何有效利用UDF。读者将了解到如何创建简单的函数,并进一步掌握处理更复杂场景的技巧。
场景设定
设想一家公司希望通过通胀模拟来预测其未来收入。公司希望了解不同通胀率将如何影响每月的收入状况。为简化模型,本文将忽略季节性因素,并基于最近一个月的已知销售额来估算当年剩余月份的收入。核心需求是,用户必须能够自行设定通胀率,并即时观察预测数字的变化。
准备数据模型
在准备数据模型时,具体操作取决于您是选择从全新的 Power BI 文件开始并加载数据,还是将此功能添加到现有文件中。首要步骤是激活预览功能:

图1 – 启用用户定义函数预览功能 (图片由作者提供)
启用该功能后,Power BI Desktop 可能需要重启。对于已有的 Power BI 文件,若要创建用户定义函数(UDF),则需要设置正确的兼容性级别。您可以选择创建一个“占位符”函数,这会自动升级兼容性级别;或者,也可以使用 Tabular Editor 将其手动设置为至少 1702:

图2 – 使用Tabular Editor升级数据库兼容级别 (图片由作者提供)
在指定字段中输入 1702 并保存即可。本文稍后将演示如何创建简单的 UDF。关于如何在 Power BI Desktop 中创建新的 UDF 的更多详情,建议查阅微软官方文档,相关链接可在文章末尾的参考资料部分找到。
添加通胀率选择功能
为了让用户能够灵活选择通胀率,需要向数据模型中添加一个参数:

图3 – 为数据模型添加数值范围参数 (图片由作者提供)
点击“数值范围”后,需要填写相应的表单:

图4 – 设置百分比范围参数 (图片由作者提供)
考虑到需要控制百分比范围,本文将范围设置为 -0.02 到 0.05,这对应着 -2% 到 5% 的区间。片刻之后,新的切片器便会自动添加到报表页面。然而,此时切片器仅显示小数形式。因此,必须更改数字格式,使其显示为百分比:

图5 – 将参数列格式化为百分比 (图片由作者提供)
经过格式化,切片器现在能按预期显示百分比数字:

图6 – 带有百分比数值的切片器 (图片由作者提供)
至此,参数设置已准备就绪,可以投入使用。
编写第一个函数
首先,创建一个UDF来返回选定的通胀率。推荐在 Tabular Editor 中编写函数,因为其 DAX 编辑器相较于 Power BI Desktop 更加高效。当然,也可以选择在 Power BI Desktop 的 DAX 查询视图中创建。在 Tabular Editor 中,导航到 Functions 节点,右键点击并选择“New User-Defined function”(新建用户定义函数):

图7 – 在Tabular Editor中创建新的用户定义函数 (图片由作者提供)
接下来,可以为函数设定名称。对于这个首个函数,将其命名为“ReturnRate”。函数的代码如下:
( Rate : DECIMAL VAL ) => Rate
在括号内,定义了输入参数。在 => 符号之后,可以输入函数的 DAX 代码。在这个简单的例子中,函数直接返回输入的参数值。现在,创建一个度量值来调用这个函数:
Get Inflation rate = ReturnRate([Inflation rate Value])
注意,度量值 [Inflation rate Value] 是在创建通胀率选择参数时自动生成的。当添加一个卡片并把这个新的度量值分配给它时,您将看到切片器中选定的通胀率:

图8 – 两个示例展示调用函数的度量值返回选定的通胀率 (图片由作者提供)
尽管这是一个基础功能,但它很好地演示了UDF的工作原理。
编写核心函数
您可能已经注意到参数定义中的关键词 VAL。正如您可以在下方两篇文章中阅读到的详细信息,DAX 中有两种传递参数的模式:
VAL:按值传递参数内容。EXPR:按表达式传递参数,它可以在函数内部像普通度量值一样使用。
在接下来的函数中,将同时使用这两种模式。以下是 MonthlyInflation 函数的完整代码:
(
Rate : DECIMAL VAL
,InputVal : EXPR
)
=>
VAR CurrentMonth = MAX( 'Date'[MonthKey] )
VAR LastMonthWithData = CALCULATE(
LASTNONBLANK( 'Date'[MonthKey]
, InputVal
)
, ALLEXCEPT( 'Date', 'Date'[Year] )
)
VAR LastValueWithData = CALCULATE(InputVal
,ALLEXCEPT('Date', 'Date'[Year])
,'Date'[MonthKey] = LastMonthWithData
)
VAR MonthDiff = CurrentMonth - LastMonthWithData
VAR Result = IF(MonthDiff<=0
,InputVal
,(1 + ( Rate * MonthDiff ) ) * LastValueWithData
)
RETURN
Result
函数的第一个参数与之前相同,仍采用 VAL 模式。第二个参数将是输入度量值的表达式。在函数内部,可以使用参数名称来更改筛选上下文等。当需要在函数内部以这种方式工作时,必须将参数设置为 EXPR。
该函数执行以下步骤:
- 获取最高的
MonthKey并将其存储在变量CurrentMonth中。CurrentMonth的内容是当前筛选上下文中月份的数值形式,例如YYYYMM。 - 获取当前年度中,输入参数(度量值)有值的最新月份,并将其存储在变量
LastMonthWithData中。 - 计算当前月份与最新有数据月份之间的差值,即
MonthDiff。这将作为计算通胀率的因子。 - 如果
MonthDiff小于或等于 0,则表示当前筛选上下文(月份)包含来自输入变量的实际数据。 - 否则,如果筛选上下文(月份)位于未来,则可以根据通胀率计算预测结果。
这里所做的是将选定的通胀率乘以自上次有数据月份(LastMonthWithData)以来的月数。
现在,可以创建一个度量值来根据选定的通胀率逐月动态计算预测结果:
Online Sales With Inflation =
MonthlyInflation([Inflation rate Value], [Sum Online Sales])
当通胀率为 3% 时,结果如下图所示:

图9 – 使用新的UDF根据选定的通胀率计算每月收入的结果 (图片由作者提供)
图中蓝色标记的月份包含实际数据,而红色标记的月份则是根据选定通胀率计算出的预测值。
UDF 的优势在于,您可以向度量值传递任何所需的 DAX 表达式。例如,可以将在线销售与零售销售相加:

图10 – 调用函数时,总销售额(在线销售加零售销售)的结果。
用于此计算的度量值代码如下:
Total Sales With Inflation =
MonthlyInflation([Inflation rate Value], [Sum Online Sales] + [Sum Retail Sales])
这无疑极大地简化了操作。尽管此计算方法非常简化,但本文旨在通过此示例展示 UDF 的强大功能和潜力。
UDF 的核心价值
那么,UDF 的核心价值究竟体现在何处?本文展示的大部分功能确实也可以通过计算组(Calculation Groups)来实现。此言不虚。然而,使用 UDF 相比于计算项(Calculation Items)来说,操作要简便得多。更重要的是,可以编写与模型无关的 UDF,并在多个数据模型中重复使用它们。例如,可以关注 DAX Lib 项目,这是一个不断增长的、独立于模型的 UDF 集合,其中包含的逻辑可以在任何数据模型中直接应用。
UDF 和计算项之间还存在其他一些显著区别:
- UDF 无法进行分组,而计算项则可以归入计算组中。
- 计算项不具备参数功能。
- UDF 可以像任何其他 DAX 函数一样被直接调用。
建议亲自尝试,以更深入地探索 UDF 的无限可能。
结论
用户定义函数(UDF)无疑是 Power BI 和 Fabric 工具集中一项卓越的补充。可以预见,随着其潜力的日益显现,掌握 UDF 的使用方法将变得愈发重要。鉴于这项功能尚处于早期引入阶段,我们需要密切关注微软未来将如何对其进行改进和完善。
当前,UDF 仍存在一些限制。您可以在此处查阅相关详情:DAX 用户定义函数的注意事项和限制。显然,该功能仍有充足的改进空间。让我们拭目以待其未来的发展。
参考资料
以下是关于用户定义函数的微软官方文档:使用 DAX 用户定义函数(预览版) – Power BI | Microsoft Learn。
这篇 SQL BI 文章详细解释了此项功能:DAX 中用户定义函数的介绍 – SQLBI。
一个免费且与模型无关的 UDF 集合:使用 DAX Lib 扩展 Power BI。
与之前的文章一样,本文使用了 Contoso 示例数据集。您可以从微软官网免费下载 ContosoRetailDW 数据集:下载链接。
