Enum
包含命名值的枚举类型。
命名值可以声明为 'string' = integer
对或 'string'
名称。ClickHouse 仅存储数字,但支持通过其名称对值进行操作。
ClickHouse 支持
- 8 位
Enum
。它可以包含最多 256 个值,这些值在[-128, 127]
范围内枚举。 - 16 位
Enum
。它可以包含最多 65536 个值,这些值在[-32768, 32767]
范围内枚举。
ClickHouse 在插入数据时会自动选择 Enum
的类型。您也可以使用 Enum8
或 Enum16
类型以确保存储大小。
使用示例
这里我们创建一个带有 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
列以与对应数字值的 Int8
或 Int16
相同的方式存储。
在文本形式读取时,ClickHouse 将值解析为字符串并从 Enum 值集中搜索相应的字符串。如果未找到,则会抛出异常。在文本形式读取时,将读取字符串并查找相应的数字值。如果未找到,则会抛出异常。在文本形式写入时,它将值写入相应的字符串。如果列数据包含垃圾(不属于有效集的数字),则会抛出异常。在二进制形式读取和写入时,它的工作方式与 Int8 和 Int16 数据类型相同。隐式默认值为具有最小数字的值。
在 ORDER BY
、GROUP BY
、IN
、DISTINCT
等等期间,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 一样。