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) │
└─────────────────────────────────────────────────────┘
通用规则和用法
每个值都分配一个数字,对于 Enum8
,范围为 -128 ... 127
,对于 Enum16
,范围为 -32768 ... 32767
。 所有字符串和数字都必须不同。 允许使用空字符串。 如果指定了此类型(在表定义中),则数字可以按任意顺序排列。 但是,顺序无关紧要。
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
等操作期间,枚举的行为方式与相应的数字相同。 例如,ORDER BY 按数值对它们进行排序。 相等和比较运算符在枚举上的工作方式与在底层数值上的工作方式相同。
枚举值不能与数字进行比较。 枚举可以与常量字符串进行比较。 如果要比较的字符串不是枚举的有效值,则会抛出异常。 IN 运算符在左侧支持枚举,在右侧支持字符串集。 这些字符串是相应枚举的值。
大多数数值和字符串操作未为枚举值定义,例如,将数字添加到枚举或将字符串连接到枚举。 但是,枚举具有自然的 toString
函数,该函数返回其字符串值。
枚举值也可以使用 toT
函数转换为数值类型,其中 T 是数值类型。 当 T 对应于枚举的底层数值类型时,此转换是零成本的。 如果仅更改值集,则可以使用 ALTER 无成本地更改 Enum 类型。 可以使用 ALTER 添加和删除 Enum 的成员(仅当删除的值从未在表中使用过时,删除才是安全的)。 作为一种安全措施,更改先前定义的 Enum 成员的数值将抛出异常。
使用 ALTER,可以将 Enum8 更改为 Enum16,反之亦然,就像将 Int8 更改为 Int16 一样。