⌘+k ctrl+k
1.1.3 (stable)
Search Shortcut cmd + k | ctrl + k
Union Type

一个UNION 类型(不要与SQL中的UNION操作符混淆)是一种能够容纳多个“替代”值之一的嵌套类型,类似于C语言中的union。主要区别在于这些UNION类型是标记联合,因此总是携带一个“标签”来指示当前持有的替代值,即使内部值本身为空。UNION类型因此更类似于C++17的std::variant、Rust的Enum或大多数函数式语言中的“和类型”。

UNION 类型必须始终至少有一个成员,虽然它们可以包含多个相同类型的成员,但标签名称必须是唯一的。UNION 类型最多可以有 256 个成员。

在底层,UNION 类型是在 STRUCT 类型的基础上实现的,并且简单地将“标签”作为第一个条目。

UNION 值可以通过 union_value(tag := expr) 函数创建,或者通过 从成员类型转换 来创建。

Example

创建一个带有UNION列的表:

CREATE TABLE tbl1 (u UNION(num INTEGER, str VARCHAR));
INSERT INTO tbl1 values (1), ('two'), (union_value(str := 'three'));

任何类型都可以隐式转换为包含该类型的UNION。如果源UNION成员是目标UNION的子集(如果转换是明确的),则任何UNION也可以隐式转换为另一个UNION

UNION 在转换为 VARCHAR 时使用成员类型的 VARCHAR 转换函数:

SELECT u FROM tbl1;
u
1

选择所有的str成员:

SELECT union_extract(u, 'str') AS str
FROM tbl1;
字符串
NULL

或者,您可以像使用STRUCTs一样使用“点语法”。

SELECT u.str
FROM tbl1;
字符串
NULL

UNION中选择当前活动的标签作为ENUM

SELECT union_tag(u) AS t
FROM tbl1;
t
num
str
str

联合类型转换

与其他嵌套类型相比,UNION允许一组隐式转换,以便在将其成员作为“子类型”处理时,能够实现无侵入且自然的使用。 然而,这些转换在设计时遵循了两个原则,以避免歧义和可能导致信息丢失的转换。这防止了UNION完全“透明”,同时仍然允许UNION类型与其成员之间存在“超类型”关系。

因此,UNION 类型通常不能隐式转换为任何其成员类型,因为不匹配目标类型的其他成员中的信息将会“丢失”。如果你想将 UNION 强制转换为其中一个成员,你应该明确使用 union_extract 函数。

唯一的例外是将UNION转换为VARCHAR时,在这种情况下,所有成员都将使用其对应的VARCHAR转换。由于所有内容都可以转换为VARCHAR,这在某种意义上是“安全”的。

转换为联合类型

如果一个类型可以隐式转换为UNION的某个成员类型,那么它总是可以隐式转换为UNION

  • 如果有多个候选者,内置的隐式转换优先级规则将决定目标类型。例如,FLOATUNION(i INTEGER, v VARCHAR) 转换将始终在 VARCHAR 之前将 FLOAT 转换为 INTEGER 成员。
  • 如果转换仍然不明确,即存在多个具有相同隐式转换优先级的候选者,则会引发错误。这通常发生在UNION包含多个相同类型的成员时,例如,FLOATUNION(i INTEGER, num INTEGER)总是模棱两可的。

那么,如果我们想创建一个具有多个相同类型成员的UNION,我们该如何消除歧义呢?通过使用union_value函数,该函数接受一个指定标签的关键字参数。例如,union_value(num := 2::INTEGER)将创建一个具有单个INTEGER类型成员且标签为numUNION。然后,这可以用于在显式(或隐式,见下文!)UNIONUNION的转换中消除歧义,例如CAST(union_value(b := 2) AS UNION(a INTEGER, b INTEGER))

联合类型之间的转换

UNION 类型可以在彼此之间进行转换,前提是源类型是目标类型的“子集”。换句话说,源 UNION 中的所有标签都必须存在于目标 UNION 中,并且所有匹配标签的类型在源和目标之间必须可以隐式转换。本质上,这意味着 UNION 类型相对于其成员是协变的。

确定 来源 目标 评论
UNION(a A, b B) UNION(a A, b B, c C)  
UNION(a A, b B) UNION(a A, b C) 如果 B 可以隐式转换为 C
UNION(a A, b B, c C) UNION(a A, b B)  
UNION(a A, b B) UNION(a A, b C) 如果 B 不能隐式转换为 C
UNION(A, B, D) UNION(A, B, C)  

比较和排序

由于UNION类型在内部是基于STRUCT类型实现的,它们可以与所有比较运算符一起使用,也可以在WHEREHAVING子句中使用,具有STRUCT相同的语义。“标签”始终存储为第一个结构体条目,这确保了UNION类型首先按“标签”进行比较和排序。

Functions

参见 Union Functions