条件函数
if
执行条件分支。
如果条件 cond
的结果为非零值,函数返回表达式 then
的结果。如果 cond
的结果为零或 NULL
,则返回 else
表达式的结果。
设置 short_circuit_function_evaluation 控制是否使用短路求值。如果启用,then
表达式仅在 cond
为 true
的行上进行评估,而 else
表达式在 cond
为 false
的行上进行评估。例如,在短路求值的情况下,执行查询 SELECT if(number = 0, 0, intDiv(42, number)) FROM numbers(10)
时不会抛出除以零的异常。
then
和 else
必须是相似的类型。
语法
别名: cond ? then : else
(三元运算符)
参数
cond
– 被评估的条件。UInt8、Nullable(UInt8) 或 NULL。then
– 如果condition
为 true,则返回的表达式。else
– 如果condition
为 false 或 NULL,则返回的表达式。
返回值
依赖于条件 cond
的 then
和 else
表达式的结果。
示例
结果:
multiIf
允许以更紧凑的格式在查询中编写 CASE 操作符。
语法
设置 short_circuit_function_evaluation 控制是否使用短路求值。如果启用,then_i
表达式仅在 ((NOT cond_1) AND (NOT cond_2) AND ... AND (NOT cond_{i-1}) AND cond_i)
为 true
的行上进行评估,cond_i
仅在 ((NOT cond_1) AND (NOT cond_2) AND ... AND (NOT cond_{i-1}))
为 true
的行上进行评估。例如,在短路求值的情况下,执行查询 SELECT multiIf(number = 2, intDiv(1, number), number = 5) FROM numbers(10)
时不会抛出除以零的异常。
参数
这个函数接受 2N+1
个参数:
cond_N
— 第 N 个被评估的条件,控制是否返回then_N
。then_N
— 当cond_N
为 true 时函数的结果。else
— 如果没有条件为 true 的函数结果。
返回值
依赖于条件 cond_N
的 then_N
或 else
表达式的结果。
示例
假设这个表:
直接使用条件结果
条件总是结果为 0
、1
或 NULL
。因此,你可以像这样直接使用条件结果:
条件中的 NULL 值
当 NULL
值涉及到条件时,结果也将是 NULL
。
因此,如果类型为 Nullable
,你应该小心构造查询。
以下示例演示了在 multiIf
中未能添加等于条件的情况。
greatest
返回一组值中的最大值。所有列表成员必须是可比较的类型。
示例:
返回的类型是 Float64,因为 UInt8 必须被提升到 64 位以进行比较。
返回的类型是 DateTime64,因为 DateTime32 必须被提升到 64 位以进行比较。
least
返回一组值中的最小值。所有列表成员必须是可比较的类型。
示例:
返回的类型是 Float64,因为 UInt8 必须被提升到 64 位以进行比较。
返回的类型是 DateTime64,因为 DateTime32 必须被提升到 64 位以进行比较。
clamp
将返回值限制在 A 和 B 之间。
语法
参数
value
– 输入值。min
– 限制下界。max
– 限制上界。
返回值
如果值小于最小值,返回最小值;如果大于最大值,返回最大值;否则返回当前值。
示例:
CASE 语句
ClickHouse 中的 CASE 表达式提供了类似于 SQL CASE 操作符的条件逻辑。它评估条件,并根据第一个匹配的条件返回值。
ClickHouse 支持两种形式的 CASE:
CASE WHEN ... THEN ... ELSE ... END
这种形式允许完全灵活性,并通过 multiIf 函数内部实现。每个条件独立评估,表达式可以包括非常量值。
CASE <expr> WHEN <val1> THEN ... WHEN <val2> THEN ... ELSE ... END
这种更紧凑的形式优化了常量值匹配,并在内部使用 caseWithExpression()
。
例如,以下是有效的:
这种形式也不要求返回的表达式为常量。
注意事项
ClickHouse 在评估任何条件之前确定 CASE 表达式(或其内部等效物,如 multiIf
)的结果类型。当返回表达式的类型不同时,例如不同时区或数字类型时,这一点非常重要。
- 结果类型基于所有分支中最大的兼容类型进行选择。
- 一旦选择了这一类型,所有其他分支将被隐式转换为此类型——即使它们的逻辑在运行时永远不会被执行。
- 对于如 DateTime64 这样的类型,其中时区是类型签名的一部分,这可能导致意外行为:第一个遇到的时区可能会用于所有分支,即使其他分支指定了不同的时区。
例如,下面所有行返回在第一个匹配分支的时区中的时间戳,即 Asia/Kolkata
在这里,ClickHouse 看到多个 DateTime64(3, <timezone>)
返回类型。它推断出共同类型为 DateTime64(3, 'Asia/Kolkata'
作为它第一次看到的类型,隐式地将其他分支转换为此类型。
可以通过转换为字符串来保留预期的时区格式: