Variant(T1, T2, ..., TN) 表示该类型的每一行
都包含一个值,该值的类型可以是 T1、T2、……、TN 中的任意一种,也可以都不是 (即 NULL 值) 。
嵌套类型的顺序无关紧要:Variant(T1, T2) = Variant(T2, T1)。
嵌套类型可以是除 Nullable(…)、LowCardinality(Nullable(…)) 和 Variant(…) 之外的任意类型。
不建议将相近的类型用作变体 (例如不同的数值类型,如
Variant(UInt32, Int64)``,或不同的日期类型,如 Variant(Date, DateTime)), 因为处理这类类型的值时可能会产生歧义。默认情况下,创建这样的 Variant类型会导致异常,但可以通过 settingallow_suspicious_variant_types` 启用。创建 Variant
Variant 类型:
if/multiIf (为此应启用设置 use_variant_as_common_type) :
use_variant_as_common_type) :
将 Variant 嵌套类型读取为子列
variant Variant(T1, T2, T3),就可以使用语法 variant.T2 读取类型为 T2 的子列。
如果 T2 可以包含在 Nullable 中,则该子列的类型为 Nullable(T2);否则为 T2。该子列的大小与原始 Variant 列相同,并且在原始 Variant 列的类型不是 T2 的所有行中,都将包含 NULL 值 (如果 T2 不能包含在 Nullable 中,则为空值) 。
也可以使用函数 variantElement(variant_column, type_name) 读取 Variant 子列。
示例:
variantType(variant_column)。它会为每一行返回一个包含 Variant 类型名称的 Enum (如果该行为 NULL,则返回 'None') 。
示例:
Variant 列与其他列之间的转换
Variant 类型的列可进行 4 种转换。
将 String 列转换为 Variant 列
String 转换为 Variant,是通过从字符串值中解析出 Variant 类型的值来实现的:
String 转换为 Variant 时禁用解析,可以关闭设置 cast_string_to_dynamic_use_inference:
将普通列转换为 Variant 列
T 的普通列转换成包含该类型的 Variant 列:
String 类型转换时始终会经过解析;如果你需要在不经过解析的情况下,将 String 列转换为 Variant 中的 String 变体,可以执行以下操作:
将 Variant 列转换为普通列
Variant 列转换为普通列。在这种情况下,所有嵌套的 Variant 都会被转换为目标类型:
将一个 Variant 转换为另一个 Variant
Variant 列转换为另一个 Variant 列,但前提是目标 Variant 列包含原始 Variant 中的所有嵌套类型:
从数据中读取 Variant 类型
Variant 类型。解析数据时,ClickHouse 会尝试将值写入最合适的 Variant 类型。
示例:
比较 Variant 类型的值
Variant 类型的值只能与相同 Variant 类型的值比较。
默认情况下,比较运算符会使用Variant 的默认实现,
分别对每个 Variant 类型进行比较。可以通过设置 use_variant_default_implementation_for_comparisons = 0 禁用此行为,
从而改用下面所述的原生 Variant 比较规则。注意,ORDER BY 始终使用原生比较。
原生 Variant 比较规则:
对于类型 Variant(..., T1, ... T2, ...) 中底层类型为 T1 的值 v1 和底层类型为 T2 的值 v2,运算符 < 的结果定义如下:
- 如果
T1 = T2 = T,则结果为v1.T < v2.T(即比较底层值) 。 - 如果
T1 != T2,则结果为T1 < T2(即比较类型名称) 。
Variant 值为特定值的行,可以采用以下任一方法:
- 将该值转换为对应的
Variant类型:
- 将
Variant子列与所需类型比较:
Array/Map/Tuple 等复杂类型的 子列 不能置于 Nullable 中,因此在类型不同的行中,它们的值将是默认值而不是 NULL:
Variant 类型不能用于 GROUP BY/ORDER BY 键;如果要使用它,请注意其特殊的比较规则,并启用 allow_suspicious_types_in_group_by/allow_suspicious_types_in_order_by 设置。
支持 Variant 的 JSONExtract 函数
JSONExtract* 函数都支持 Variant 类型:
带 Variant 参数的函数
Variant 类型参数。
从 26.1 版本开始,如果某个未显式处理 Variant 类型的函数接收到一个 Variant 列,ClickHouse 会:
- 从 Variant 列中提取每种 Variant 类型
- 分别对每种 Variant 类型执行该函数
- 根据结果类型以适当方式合并结果
-
结果类型不同:
Variant(T1, T2, ...) -
类型不兼容:对不兼容的 Variant 返回
NULL
错误处理: 当函数无法处理某种 Variant 类型时,只有类型相关的错误 (ILLEGAL_TYPE_OF_ARGUMENT,
TYPE_MISMATCH, CANNOT_CONVERT_TYPE, NO_COMMON_TYPE) 会被捕获,并使这些行返回 NULL。其他错误 (如
除以零或内存不足) 仍会正常抛出,以避免掩盖真实问题。
类型不匹配时的行为
variant_throw_on_type_mismatch 用于控制当函数应用于 Variant 列,而某一行实际存储的类型与该函数不兼容时的处理方式:
true(默认) — 在遇到第一个不兼容的行时抛出异常 (ILLEGAL_TYPE_OF_ARGUMENT) 。false— 对不兼容的行返回NULL,同时保留兼容行的结果。