Name | Description |
---|---|
enum | 字典编码,表示列的所有可能字符串值。 |
枚举类型表示一个字典数据结构,其中包含列的所有可能唯一值。例如,存储星期几的列可以是一个包含所有可能日期的枚举。枚举对于基数较低(即不同值较少)的字符串列特别有用。这是因为该列只存储枚举字典中字符串的数字引用,从而大大节省磁盘存储空间并加快查询性能。
枚举定义
枚举类型可以从一组硬编码的值或从一个返回单列VARCHAR
的select语句创建。select语句中的值集将被去重,但如果枚举是从一组硬编码的值创建的,则可能不会有任何重复。
使用硬编码值创建枚举:
CREATE TYPE ⟨enum_name⟩ AS ENUM ([⟨value_1⟩, ⟨value_2⟩,...]);
使用返回单列VARCHAR
的SELECT
语句创建枚举:
CREATE TYPE ⟨enum_name⟩ AS ENUM (select_expression⟩);
例如:
创建新的用户定义类型 'mood' 作为枚举:
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
这将失败,因为 mood
类型已经存在:
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy', 'anxious');
这将失败,因为枚举不能包含NULL
值:
CREATE TYPE breed AS ENUM ('maltese', NULL);
这将失败,因为枚举值必须是唯一的:
CREATE TYPE breed AS ENUM ('maltese', 'maltese');
从选择语句创建一个枚举。首先创建一个值的示例表:
CREATE TABLE my_inputs AS
SELECT 'duck' AS my_varchar UNION ALL
SELECT 'duck' AS my_varchar UNION ALL
SELECT 'goose' AS my_varchar;
使用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
(情绪类型):
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';
名称 | 当前心情 |
---|---|
帕利亚奇 | 悲伤 |
如果您正在从文件导入数据,您可以在导入之前为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';
枚举 vs. 字符串
DuckDB枚举在必要时会自动转换为VARCHAR
类型。这一特性允许枚举列在任何VARCHAR
函数中使用。此外,它还允许在不同枚举列之间或枚举列与VARCHAR
列之间进行比较。
例如:
Regexp_matches 是一个接受 VARCHAR 的函数,因此 current_mood 被转换为 VARCHAR:
SELECT regexp_matches(current_mood, '.*a.*') AS contains_a
FROM person;
contains_a |
---|
真 |
NULL |
真 |
假 |
创建一个新的心情和表格:
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_mood
和future_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;
公司 |
---|
true |
SELECT unnest(['ok'::mood, 'happy'::mood, 'sad'::mood]) AS m
ORDER BY m;
m |
---|
悲伤 |
好的 |
快乐 |
Functions
参见 Enum Functions。