⌘+k ctrl+k
1.3 (稳定版)
搜索快捷键 cmd + k | ctrl + k
联合类型

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

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

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

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

示例

创建一个包含UNION列的表

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

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

当转换为VARCHAR时,UNION使用成员类型的VARCHAR转换函数

SELECT u FROM tbl1;
u
1

选择所有str成员

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

或者,您可以像对STRUCT类型一样使用“点语法”。

SELECT u.str
FROM tbl1;
str
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)的类型转换将始终优先将FLOAT转换为INTEGER成员,而不是VARCHAR
  • 如果类型转换仍然存在歧义,即有多个具有相同隐式转换优先级的候选类型,则会引发错误。这通常发生在UNION包含多个相同类型的成员时,例如,FLOATUNION(i INTEGER, num INTEGER)总是存在歧义。

那么,如果我们想创建包含多个相同类型成员的UNION,该如何消除歧义呢?通过使用union_value函数,它接受一个指定标签的关键字参数。例如,union_value(num := 2::INTEGER)将创建一个UNION,其中包含一个类型为INTEGER的成员,标签为num。然后,这可以在显式(或隐式,请继续阅读下文!)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类型首先按“标签”进行比较和排序。

函数

参见联合函数