Enum
| Name | Description |
|---|---|
ENUM | Dictionary representing all possible string values of a column |
The enum type represents a dictionary data structure with all possible unique values of a column. For example, a column storing the days of the week can be an enum holding all possible days. Enums are particularly interesting for string columns with low cardinality (i.e., fewer distinct values). This is because the column only stores a numerical reference to the string in the enum dictionary, resulting in immense savings in disk storage and faster query performance.
Creating Enums
You can create an enum using hardcoded values:
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');You can create enums in a specific schema:
CREATE SCHEMA my_schema;
CREATE TYPE my_schema.mood AS ENUM ('sad', 'ok', 'happy');Anonymous enums can be created on the fly during casting:
SELECT 'clubs'::ENUM ('spades', 'hearts', 'diamonds', 'clubs') AS suit; suit------- clubsYou can also create an enum using a SELECT statement that returns a single column of VARCHARs.
The set of values from the select statement will be deduplicated automatically,
and NULL values will be ignored:
CREATE TYPE region AS ENUM (SELECT region FROM sales_data);If you are importing data from a file, you can create an enum for a VARCHAR column before importing:
CREATE TYPE region AS ENUM (SELECT region FROM 'sales_data.csv');
CREATE TABLE sales_data (amount INTEGER, region region);
COPY sales_data FROM 'sales_data.csv';Using Enums
Enum values are case-sensitive, so 'maltese' and 'Maltese' are considered different values:
CREATE TYPE breed AS ENUM ('maltese', 'Maltese');
-- Will return falseSELECT 'maltese'::breed = 'Maltese'::breed;
-- Will errorSELECT 'MALTESE'::breed; ?column?---------- f
error db error: ERROR: Could not convert string 'MALTESE' to UINT8After an enum has been created, it can be used anywhere a standard built-in type is used. For example, we can create a table with a column that references the enum.
CREATE TABLE person ( name TEXT, current_mood mood);
INSERT INTO person VALUES ('Pedro', 'happy'), ('Mark', NULL), ('Pagliacci', 'sad'), ('Mr. Mackey', 'ok');The following query will fail since the mood type does not have a quackity-quack value.
INSERT INTO person VALUES ('Hannes', 'quackity-quack');error db error: ERROR: Could not convert string 'quackity-quack' to UINT8Enums vs. Strings
SereneDB enums are automatically cast to VARCHAR types whenever necessary.
This characteristic allows for comparisons between different enums, or an enum and a VARCHAR column.
It also allows for an enum to be used in any VARCHAR function. For example:
SELECT current_mood, regexp_matches(current_mood, '.*a.*') AS contains_a FROM person; current_mood | contains_a--------------+------------ happy | t NULL | NULL sad | t ok | fWhen comparing two different enum types, SereneDB will cast both to strings and perform a string comparison:
CREATE TYPE new_mood AS ENUM ('happy', 'anxious');
SELECT * FROM personWHERE current_mood = 'happy'::new_mood; name | current_mood-------+-------------- Pedro | happyWhen comparing an enum to a VARCHAR, SereneDB will cast the enum to VARCHAR and perform a string comparison:
SELECT * FROM personWHERE current_mood = name;name current_moodWhen comparing against a constant string, SereneDB will perform an optimization
and try_cast(⟨constant string⟩, enum_type) so that physically
we are doing an integer comparison instead of a string comparison
(but logically it is still a string comparison):
SELECT * FROM personWHERE current_mood = 'sad'; name | current_mood-----------+-------------- Pagliacci | sadWarning This means that comparing against a random (non-equivalent) string always results in
false(and does not error):
SELECT * FROM personWHERE current_mood = 'bogus';name current_moodIf you want to enforce type-safety, cast to the enum explicitly:
SELECT * FROM personWHERE current_mood = 'bogus'::mood;error db error: ERROR: Could not convert string 'bogus' to UINT8Ordering of Enums
Enum values are ordered according to their order in the enum's definition. For example:
CREATE TYPE priority AS ENUM ('low', 'medium', 'high');
SELECT 'low'::priority < 'high'::priority AS comp; comp------ tSELECT unnest(['medium'::priority, 'high'::priority, 'low'::priority]) AS mORDER BY m; m-------- low medium highCREATE TABLE tasks (name TEXT, priority_level priority);
INSERT INTO tasks VALUES ('a', 'low'), ('b', 'medium'), ('c', 'high');
-- WARNING!-- Equivalent to `WHERE priority_level::VARCHAR >= 'medium'`SELECT * FROM tasksWHERE priority_level >= 'medium'; name | priority_level------+---------------- b | medium c | highSo, if you want to e.g. "get all priorities at or above medium" then explicitly cast to the enum type:
SELECT * FROM tasksWHERE priority_level >= 'medium'::priority; name | priority_level------+---------------- b | medium c | highFunctions
See Enum Functions.
For example, show the available values in the mood enum using the enum_range function:
SELECT enum_range(NULL::mood) AS my_enum_range; my_enum_range---------------- {sad,ok,happy}Enum Removal
Enum types are stored in the catalog, and a catalog dependency is added to each table that uses them. It is possible to drop an enum from the catalog using the following command:
DROP TYPE ⟨enum_name⟩;Currently, it is possible to drop enums that are used in tables without affecting the tables.
Warning This behavior of the enum removal feature is subject to change. In future releases, it is expected that any dependent columns must be removed before dropping the enum, or the enum must be dropped with the additional
CASCADEparameter.