基础
IF 是最常见的逻辑函数,用于条件判断,它的语法和 Excel 相同。SWITCH 是多层 IF 的简化形式,本质是 IF 嵌套,但是写法更优雅,以下是两个示例:
-------- IF 形式 ------------ SizeDesc = IF ( Product[Size] = "S", "Small", IF ( Product[Size] = "M", "Medium", IF ( Product[Size] = "L", "Large", IF ( Product[Size] = "XL", "Extra Large", "Other" ) ) ) ) -------- SWITCH 等价形式 ---------- SizeDesc = SWITCH ( Product[Size], "S", "Small", "M", "Medium", "L", "Large", "XL", "Extra Large", "Other" )
除了用第一参数返回的值作为判断条件,SWITCH 还有一种实用的写法,适合用在逻辑判断中,在逻辑函数一文中介绍过,
SWITCH ( TRUE (), Product[Size] = "XL" && Product[Color] = "Red", "Red and XL", Product[Size] = "XL" && Product[Color] = "Blue", "Blue and XL", Product[Size] = "L" && Product[Color] = "Green", "Green and L" )
使用 TRUE 作为第一参数表示:“返回条件求值为 TRUE 的第一个结果”。
注意
IF 函数看似结构简单,但隐藏了一些容易被忽视的细节。
变体类型
变体数据类型用于可能返回不同数据类型的度量值,主要与 IF 配合使用,变体类型取决于度量值使用的条件表达式。例如,下面的语句可以返回整数或字符串,所以它返回一个变体类型:
IF ( [measure] > 0, 1, "N/A" )
变体只适用于度量值,不能用于计算列,因为计算列必须具有统一的数据类型
标量函数
IF 和 SWITCH 都是标量函数,所以它们只能输出标量值,不能输出表,你不能在 IF 的条件中直接返回表表达式,所以下面的写法是错误的:
VAR Granularity = IF ( SELECTEDVALUE ( 'Dynamic Axis'[Granularity] ) = "Monthly", DATESMTD ( 'Calendar'[date] ), DATESYTD ( 'Calendar'[date] ) ) RETURN CALCULATE ( SUM ( [SomeField] ), Granularity )
逻辑表达式的一种特殊情况
当 IF 的返回条件中出现一个空值和一个逻辑表达式(即 TRUE() 或 FALSE() 时),整个公式返回逻辑表达式,忽略空值。
IF ( 1 = 1, BLANK(), TRUE() ) 返回 FALSE
使用变量优化 IF 和 SWITCH
在 DAX 表达式中使用变量替换相同度量值的多次引用可以提高公式可读性、优化公式的效率,因为正确地使用变量可以防止对同一表达式多次计算。然而,在某些情况下,变量的使用也可能适得其反,对性能产生负面影响。
短路计算
在这种多条件计算中,我们希望公式在命中指定的分支时才计算对应的变量。在 IF 和 SWITCH 函数的计值过程中,这种优化策略称为短路计算,做法是将特定筛选器应用于 IF 或 SWITCH 的每个求值分支的筛选上下文。由于 Sales vSlow 度量值中的变量是在 IF 和 SWITCH 之前定义的,因此分支中的筛选上下文无法影响变量的计算。所有变量(和所有度量值)的计算将不考虑示例报表的 Period 切片器中所做的选择。
变量使用规范
在特定场景中,此特性可能对 DAX 度量值的性能产生严重影响,因此,使用变量最好遵循以下规则:
高老师您好:
在本文中您提到“如果变量定义在条件判断之前,则无论条件是否命中,都将计算该变量”,
而在《理解变量》一文中您提到“无论出于什么原因,如果没有被使用,那么这个变量将永远不会被计算”,
这两句话冲突吗?
谢谢老师!
老师你好,对于switch和if的内部机制不太理解,我有两个测试公式:
CG_switch :=
var tp = SELECTEDVALUE(slicer1[type1])
var rst =
SWITCH(
tp,
“a”, SUM(test_data[data1]),
“b”, SUM(test_data[data2]),
“c”, “no cal”
)
return
rst
CG_no_switch :=
SUM(test_data[data1])
其中slicer1[type1]只有”a”, “b”, “c”三个值,没有任何关系。我在desktop上创建两个表格,分别放入上面两个度量值,然后切片器选中”a”,那么两个表格都计算同一个逻辑,即 SUM(test_data[data1])。
我使用Dax studio进行测试,发现性能差距很明显,例如CG_no_switch只需要2ms,而CG_switch需要6ms左右,而且使用FE较多。另外CG_no_switch的查询计划很简短,而CG_switch很长,大概10倍以上,我看不懂。
那么请问为什么switch会如此表现呢?如何提升它的性能呢?
这是我实际工作遇到的问题,数据量大的时候非常明显,因此对switch和if这类判断函数有顾虑,明显内部机制没有看上去简单,存在性能隐患,或者是否我使用不当呢。谢谢!
高老师 我在设计损益表对比维度的度量值公式如下,但在表格取数时只能取到[1.1.2-ACT Full P&l]-[1.1.1-BGT Full P&l],无法取到[1.1.2-ACT Full P&l]这个结果 这是什么原因呢?和公式有关吗?
1.1.2-对比 Full p&l =
IF(SELECTEDVALUE(‘对比维度'[对比]) = “B/(W) Bgt”,[1.1.2-ACT Full P&l]-[1.1.1-BGT Full P&l],[1.1.2-ACT Full P&l]
)
老师,关于逻辑表达式的特殊情况那个例子我很不明白,而且我自己测试的跟文中的结果也不一样。
IF(1=1,100,FALSE) 这个我测试的结果是返回100,并不是文中写的TRUE.
IF ( 1 = 1, BLANK(), TRUE ) 我也不明白为啥会返回FALSE.前面不是说“当 IF 的返回条件中出现一个逻辑表达式,即“true”或“false”时,整个公式返回逻辑表达式或文本”吗,这个公式的逻辑表达式是“TRUE”,为什么结果不是返回“TRUE”呢?是我理解错您的意思了吗?
“Sales YTDOY 公式对于 SUMX 第一参数中的月份,每月只计算一次[Sales Amount]和[Sales LY],在后续的 IF 条件中重复调用。对比下面的公式,你会发现这种写法的效率高的多。”中的“对比下面的公式,你会发现这种写法的效率高的多”表达意思应该是:对比上面公式,你会发现下面的写法效率高的多。原句是不是有点歧义,还是我没有理解透,我理解的是原文表达的意思下面的写法比上面的写法高效的多
https://study.163.com/course/introduction.htm?courseId=1004898001#/courseDetail?tab=1
高老师,这个链接里的课程还能买吗?
我看您在资料提到6月之后不再卖了。
高飞老师,我用switch,出现以下报错是什么原因?
文中第一段代码第3行 Product[Size] 前多写了一个字母D。