跳至主要内容

Enum

包含命名值的枚举类型。

命名值可以声明为 'string' = integer 对或 'string' 名称。ClickHouse 仅存储数字,但支持通过其名称对值进行操作。

ClickHouse 支持

  • 8 位 Enum。它可以包含最多 256 个值,这些值在 [-128, 127] 范围内枚举。
  • 16 位 Enum。它可以包含最多 65536 个值,这些值在 [-32768, 32767] 范围内枚举。

ClickHouse 在插入数据时会自动选择 Enum 的类型。您也可以使用 Enum8Enum16 类型以确保存储大小。

使用示例

这里我们创建一个带有 Enum8('hello' = 1, 'world' = 2) 类型列的表

CREATE TABLE t_enum
(
x Enum('hello' = 1, 'world' = 2)
)
ENGINE = TinyLog

类似地,您可以省略数字。ClickHouse 会自动分配连续的数字。默认情况下,数字从 1 开始分配。

CREATE TABLE t_enum
(
x Enum('hello', 'world')
)
ENGINE = TinyLog

您也可以为第一个名称指定合法的起始数字。

CREATE TABLE t_enum
(
x Enum('hello' = 1, 'world')
)
ENGINE = TinyLog
CREATE TABLE t_enum
(
x Enum8('hello' = -129, 'world')
)
ENGINE = TinyLog
Exception on server:
Code: 69. DB::Exception: Value -129 for element 'hello' exceeds range of Enum8.

x 只能存储类型定义中列出的值:'hello''world'。如果您尝试保存任何其他值,ClickHouse 将引发异常。此 Enum 的 8 位大小会自动选择。

INSERT INTO t_enum VALUES ('hello'), ('world'), ('hello')
Ok.
INSERT INTO t_enum values('a')
Exception on client:
Code: 49. DB::Exception: Unknown element 'a' for type Enum('hello' = 1, 'world' = 2)

当您从表中查询数据时,ClickHouse 会输出来自 Enum 的字符串值。

SELECT * FROM t_enum
┌─x─────┐
│ hello │
│ world │
│ hello │
└───────┘

如果您需要查看行的数字等效项,则必须将 Enum 值强制转换为整数类型。

SELECT CAST(x, 'Int8') FROM t_enum
┌─CAST(x, 'Int8')─┐
│ 1 │
│ 2 │
│ 1 │
└─────────────────┘

要在查询中创建 Enum 值,您也需要使用 CAST

SELECT toTypeName(CAST('a', 'Enum(\'a\' = 1, \'b\' = 2)'))
┌─toTypeName(CAST('a', 'Enum(\'a\' = 1, \'b\' = 2)'))─┐
│ Enum8('a' = 1, 'b' = 2) │
└─────────────────────────────────────────────────────┘

一般规则和用法

每个值在 -128 ... 127 范围内分配一个数字,用于 Enum8,或在 -32768 ... 32767 范围内分配一个数字,用于 Enum16。所有字符串和数字都必须不同。空字符串是允许的。如果指定了此类型(在表定义中),则数字可以按任意顺序。但是,顺序并不重要。

Enum 中的字符串和数字值均不能为 NULL

Enum 可以包含在 Nullable 类型中。因此,如果您使用以下查询创建表

CREATE TABLE t_enum_nullable
(
x Nullable( Enum8('hello' = 1, 'world' = 2) )
)
ENGINE = TinyLog

它不仅可以存储 'hello''world',还可以存储 NULL

INSERT INTO t_enum_nullable Values('hello'),('world'),(NULL)

在 RAM 中,Enum 列以与对应数字值的 Int8Int16 相同的方式存储。

在文本形式读取时,ClickHouse 将值解析为字符串并从 Enum 值集中搜索相应的字符串。如果未找到,则会抛出异常。在文本形式读取时,将读取字符串并查找相应的数字值。如果未找到,则会抛出异常。在文本形式写入时,它将值写入相应的字符串。如果列数据包含垃圾(不属于有效集的数字),则会抛出异常。在二进制形式读取和写入时,它的工作方式与 Int8 和 Int16 数据类型相同。隐式默认值为具有最小数字的值。

ORDER BYGROUP BYINDISTINCT 等等期间,Enum 的行为与相应的数字相同。例如,ORDER BY 按数字对它们进行排序。相等和比较运算符在 Enum 上的工作方式与在底层数字值上相同。

Enum 值不能与数字进行比较。Enum 可以与常量字符串进行比较。如果与之比较的字符串不是 Enum 的有效值,则会抛出异常。IN 运算符支持左侧为 Enum,右侧为字符串集。字符串是相应 Enum 的值。

大多数数字和字符串运算未针对 Enum 值定义,例如:将数字添加到 Enum 或将字符串连接到 Enum。但是,Enum 具有一个自然的 toString 函数,该函数返回其字符串值。

Enum 值也可以使用 toT 函数转换为数字类型,其中 T 是数字类型。当 T 对应于枚举的底层数字类型时,此转换是零成本的。如果只更改了值的集合,则可以使用 ALTER 以零成本更改 Enum 类型。可以使用 ALTER 添加和删除 Enum 的成员(仅当从未在表中使用过删除的值时,删除才是安全的)。作为安全措施,更改先前定义的 Enum 成员的数字值将抛出异常。

使用 ALTER,可以将 Enum8 更改为 Enum16,反之亦然,就像将 Int8 更改为 Int16 一样。