⌘+k ctrl+k
1.3 (稳定版)
搜索快捷键 cmd + k | ctrl + k
枚举数据类型
名称 描述
ENUM 表示列所有可能字符串值的字典

枚举类型表示一个字典数据结构,其中包含列所有可能的唯一值。例如,存储一周中各天的列可以是一个包含所有可能日期的枚举。枚举对于基数低(即,不同值较少)的字符串列尤其有用。这是因为该列仅存储枚举字典中字符串的数值引用,从而大大节省了磁盘存储并提高了查询性能。

枚举定义

枚举类型可以从硬编码的值集创建,也可以从返回单列 VARCHAR 的 SELECT 语句创建。SELECT 语句中的值集将被去重,但如果枚举是从硬编码值集创建的,则可能没有任何重复项。

使用硬编码值创建枚举

CREATE TYPE enum_name AS ENUM (value_1, value_2, ...);

使用返回单列 VARCHARSELECT 语句创建枚举

CREATE TYPE enum_name AS ENUM (select_expression);

枚举也可以在类型转换过程中动态创建

SELECT 'some_string'::ENUM (value_1, value_2, ...);

示例

创建新的用户定义类型 mood 作为枚举

CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');

从 select 语句创建枚举。首先创建一个示例值表

CREATE TABLE my_inputs AS
    FROM (VALUES ('duck'), ('duck'), ('goose')) t(my_varchar);

动态创建一个匿名枚举值

SELECT 'happy'::ENUM ('sad', 'ok', 'happy');

此语句将失败,因为枚举不能包含 NULL

CREATE TYPE breed AS ENUM ('maltese', NULL);

此语句将失败,因为枚举值必须是唯一的

CREATE TYPE breed AS ENUM ('maltese', 'maltese');

使用 my_varchar 列中的唯一字符串值创建枚举

CREATE TYPE birds AS ENUM (SELECT my_varchar FROM my_inputs);

使用 enum_range 函数显示 birds 枚举中的可用值

SELECT enum_range(NULL::birds) AS my_enum_range;
my_enum_range
[duck, goose]

枚举用法

枚举创建后,可以在任何使用标准内置类型的地方使用。例如,我们可以创建一个表,其中一列引用该枚举。

创建一个表 person,其中包含属性 name(字符串类型)和 current_mood(mood 类型)

CREATE TABLE person (
    name TEXT,
    current_mood mood
);

person 表中插入元组

INSERT INTO person
VALUES ('Pedro', 'happy'), ('Mark', NULL), ('Pagliacci', 'sad'), ('Mr. Mackey', 'ok');

以下查询将失败,因为 mood 类型没有 quackity-quack 值。

INSERT INTO person
VALUES ('Hannes', 'quackity-quack');

字符串 sad 被转换为 mood 类型,返回一个数值引用。这使得比较成为数值比较而不是字符串比较。

SELECT *
FROM person
WHERE current_mood = 'sad';
name current_mood
Pagliacci sad

如果您正在从文件导入数据,您可以在导入前为 VARCHAR 列创建枚举。鉴于此,以下子查询会自动选择唯一的不同值

CREATE TYPE mood AS ENUM (SELECT mood FROM 'path/to/file.csv');

然后,您可以创建一个具有枚举类型的表,并使用任何数据导入语句进行导入

CREATE TABLE person (name TEXT, current_mood mood);
COPY person FROM 'path/to/file.csv';

枚举与字符串

DuckDB 枚举在必要时会自动转换为 VARCHAR 类型。此特性允许枚举列在任何 VARCHAR 函数中使用。此外,它还允许不同枚举列之间,或枚举与 VARCHAR 列之间的比较。

例如

Regexp_matches 是一个接受 VARCHAR 的函数,因此 current_mood 被转换为 VARCHAR

SELECT regexp_matches(current_mood, '.*a.*') AS contains_a
FROM person;
contains_a
true
NULL
true
false

创建一个新的 mood 和表

CREATE TYPE new_mood AS ENUM ('happy', 'anxious');
CREATE TABLE person_2 (
    name text,
    current_mood mood,
    future_mood new_mood,
    past_mood VARCHAR
);

由于 current_moodfuture_mood 列是基于不同的枚举类型构建的,DuckDB 会将两个枚举都转换为字符串并执行字符串比较

SELECT *
FROM person_2
WHERE current_mood = future_mood;

在比较 past_mood 列(字符串)时,DuckDB 会将 current_mood 枚举转换为 VARCHAR 并执行字符串比较

SELECT *
FROM person_2
WHERE current_mood = past_mood;

枚举删除

枚举类型存储在目录中,并且会为每个使用它们的表添加目录依赖项。可以使用以下命令从目录中删除枚举

DROP TYPE enum_name;

目前,可以在不影响表的情况下删除表中使用的枚举。

警告:枚举删除功能的此行为可能会更改。在未来的版本中,预计在删除枚举之前必须删除任何依赖列,或者必须使用附加的 CASCADE 参数删除枚举。

枚举比较

枚举值根据其在枚举定义中的顺序进行比较。例如:

CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
SELECT 'sad'::mood < 'ok'::mood AS comp;
comp
true
SELECT unnest(['ok'::mood, 'happy'::mood, 'sad'::mood]) AS m
ORDER BY m;
m
sad
ok
happy

函数

参见枚举函数