How to Use Enumerated Data Types with PostgreSQL
Introduction
In the PostgreSQL database server, an enumerated (enum) type is a custom data type containing a list of permitted input values. You can map the PostgreSQL enum data types to a table using the CREATE TABLE
command. Enum data types are suitable in scenarios where you want to move some validation logic to the database level and prevent users from inserting invalid data.
Also, only use the enum data types in a table column that requires a clear set of items (usually around ten) that rarely change (For instance, colors, continents, and product types). Otherwise, lookup tables with correctly linked foreign keys might be more appropriate.
This guide shows you how to use a managed PostgreSQL database cluster to define and use custom enum data types on Ubuntu 20.04.
Prerequisites
To test this guide:
Sign in to your Vultr account. Locate Products on the left side menu, then click Databases on the navigation menu. Click the name of your managed PostgreSQL database cluster under the Managed Database Name. Under the Overview tab, locate Connection Details. This guide uses the following sample connection details:
username:
vultradmin
password:
EXAMPLE_POSTGRESQL_PASSWORD
host:
SAMPLE_POSTGRESQL_DB_HOST_STRING.vultrdb.com
port:
16751
1. Set Up a Sample Database
Before creating the enum data types, establish an SSH
connection to your Linux server and execute the following steps to set up a sample database:
Install the
postgresql-client
package, a command-line client that allows you to establish a secure connection to your managed PostgreSQL database cluster.$ sudo apt update $ sudo apt install -y postgresql-client
Use the PostgreSQL client (
psql
) to connect to the managed PostgreSQL cluster. Replace the values after-h
,-p
,-U
with the correcthost
,port
, andusername
from the managed database cluster.$ psql -h SAMPLE_POSTGRESQL_DB_HOST_STRING.vultrdb.com -p 16751 -U vultradmin defaultdb
Output.
Password for user vultradmin:
Enter the PostgreSQL database cluster's password and press Enter to proceed.
Output.
defaultdb=>
Run the following SQL command to set up a sample
company_db
database.defaultdb=> CREATE DATABASE company_db;
Output.
CREATE DATABASE
Connect to the new
company_db
.defaultdb=> \c company_db;
Output.
You are now connected to database "company_db" as user "vultradmin".
After setting up the database, proceed to the next step to create enum data types.
2. Create Sample Enum Data Types
In PostgreSQL, you should follow the syntax below to create an enum data type:
=> CREATE TYPE SAMPLE_ENUM_DATA_TYPE AS ENUM (SAMPLE_ENUM_VALUES);
The PostgreSQL enum command explained:
SAMPLE_ENUM_DATA_TYPE
: This is a unique enum data type name. The name must be descriptive enough to avoid confusion.SAMPLE_ENUM_VALUES
: This is a comma-separated list containing quoted enum values (For instance,'RED', 'BLUE', 'ORANGE'
).
After familiarizing yourself with the enum data type syntax, follow the steps below to create a few samples:
Create a
product_type_enum
data type to mark products as eitherPHYSICAL
(tangible goods) orNON-PHYSICAL
(services).company_db=> CREATE TYPE product_type_enum AS ENUM ('PHYSICAL', 'NON-PHYSICAL');
Output.
CREATE TYPE
Create an
availability_enum
data type to set products' availability. TheONLINE
status shows that a product is only available from the company's website. TheSTOREFRONT
status shows that the product is only available for pickups. TheBOTH
status shows that a product is available both on the website and in the company's physical store.company_db=> CREATE TYPE availability_enum AS ENUM ('ONLINE', 'STOREFRONT', 'BOTH');
Output.
... CREATE TYPE
Ensure your
product_type_enum
list is in place.company_db=> SELECT UNNEST(enum_range(null::product_type_enum)) AS product_type_enum;
Output.
product_type_enum ---------------- PHYSICAL NON-PHYSICAL (2 rows)
Run the following query to verify the
availability_enum
data type values.company_db=> SELECT UNNEST(enum_range(null::availability_enum)) AS availability_enum;
Output.
availability_enum -------------------- ONLINE STOREFRONT BOTH (3 rows)
With the two sample custom enum data types in place, proceed to the next step to create a table.
3. Create Enum Type Columns and Query Data
This step shows you how to create a table using your custom enum data types, inserting data, and querying the table to confirm changes. In PostgreSQL, creating a table that uses some custom enum data types is not complicated. Use the following syntax.
=> CREATE TABLE SAMPLE_TABLE_NAME (
SAMPLE_COLUMN_NAME SAMPLE_ENUM_DATA_TYPE
);
Create a sample
products
table. Ensure theproduct_type
andavailability
columns use theproduct_type_enum
andavailability_enum
data types.company_db=> CREATE TABLE products ( product_id SERIAL PRIMARY KEY, product_name VARCHAR(50), sku VARCHAR(50), product_type product_type_enum, availability availability_enum, retail_price FLOAT );
Output.
CREATE TABLE
Insert sample data into the
products
table.company_db=> INSERT INTO products (product_name, sku, product_type, availability, retail_price) VALUES ('ORANGE JUICE', 'FNT123C', 'PHYSICAL', 'ONLINE', '23.55'); INSERT INTO products (product_name, sku, product_type, availability, retail_price) VALUES ('BLUE PEN', 'BP429D', 'PHYSICAL', 'BOTH', 0.85); INSERT INTO products (product_name, sku, product_type, availability, retail_price) VALUES ('COMPUTER ANTIVIRUS', 'CMP12A', 'NON-PHYSICAL', 'ONLINE', 24.99); INSERT INTO products (product_name, sku, product_type, availability, retail_price) VALUES ('FRESH KALES', 'FR127K', 'NON-PHYSICAL', 'STOREFRONT', 3.45);
Output
... INSERT 0 1
Query the
products
table to ensure everything is in place.company_db=# SELECT product_id, product_name, sku, product_type, availability, retail_price FROM products;
Output.
product_id | product_name | sku | product_type | availability | retail_price ------------+--------------------+---------+--------------+--------------+-------------- 1 | ORANGE JUICE | FNT123C | PHYSICAL | ONLINE | 23.55 2 | BLUE PEN | BP429D | PHYSICAL | BOTH | 0.85 3 | COMPUTER ANTIVIRUS | CMP12A | NON-PHYSICAL | ONLINE | 24.99 4 | FRESH KALES | FR127K | NON-PHYSICAL | STOREFRONT | 3.45 (4 rows)
Review the validation policy of the enum data types by trying to enter a record with an invalid
product_type
value.company_db=# INSERT INTO products (product_name, sku, product_type, availability, retail_price) VALUES ('MINERAL WATER', 'MN857P', 'WATER', 'STOREFRONT', 8.65);
Output.
ERROR: invalid input value for enum product_type_enum: "WATER" LINE 1: ... retail_price) VALUES ('MINERAL WATER', 'MN857P', 'WATER', '...
The table structure and records are now in place. Learn to sort and compare data records using the enum data type columns in the next step.
4. Sort and Compare PostgreSQL Enum Data
When sorting values by an enum type column, PostgreSQL considers the original order declared when you first defined the enum type values.
Query the
products
table and use the...ORDER BY availability
clause to see the behavior in action.company_db=# SELECT product_id, product_name, sku, product_type, availability, retail_price FROM products ORDER BY availability;
Verify the output below. As you can see, PostgreSQL sorts the availability column using the order that you defined when creating the
availability_enum
data type. That is, PostgreSQL doesn't order the records alphabetically.product_id | product_name | sku | product_type | availability | retail_price ------------+--------------------+---------+--------------+--------------+-------------- 1 | ORANGE JUICE | FNT123C | PHYSICAL | ONLINE | 23.55 3 | COMPUTER ANTIVIRUS | CMP12A | NON-PHYSICAL | ONLINE | 24.99 4 | FRESH KALES | FR127K | NON-PHYSICAL | STOREFRONT | 3.45 2 | BLUE PEN | BP429D | PHYSICAL | BOTH | 0.85 (4 rows)
Override the sort order behavior by casting the enum column to text when running the
ORDER BY
clause.company_db=# SELECT product_id, product_name, sku, product_type, availability, retail_price FROM products ORDER BY availability::text;
Output.
product_id | product_name | sku | product_type | availability | retail_price ------------+--------------------+---------+--------------+--------------+-------------- 2 | BLUE PEN | BP429D | PHYSICAL | BOTH | 0.85 1 | ORANGE JUICE | FNT123C | PHYSICAL | ONLINE | 23.55 3 | COMPUTER ANTIVIRUS | CMP12A | NON-PHYSICAL | ONLINE | 24.99 4 | FRESH KALES | FR127K | NON-PHYSICAL | STOREFRONT | 3.45 (4 rows)
Run the following query that uses a comparison operator (
>
) to list all products having aproduct_type
enum type index that appears after thePHYSICAL
value in the originalproduct_type
enum list.company_db=# SELECT product_id, product_name, sku, product_type, availability, retail_price FROM products WHERE product_type > 'PHYSICAL';
Output.
product_id | product_name | sku | product_type | availability | retail_price ------------+--------------------+--------+--------------+--------------+-------------- 3 | COMPUTER ANTIVIRUS | CMP12A | NON-PHYSICAL | ONLINE | 24.99 4 | FRESH KALES | FR127K | NON-PHYSICAL | STOREFRONT | 3.45 (2 rows)
After sorting data by enum columns, proceed next to learn how to manage existing enum lists.
5. Managing Enum Types and Values
The PostgreSQL server provides several commands for managing the enum data types and linked values. Test the commands in the following sections.
5.1. Change An Enum Type Name
In the PostgreSQL server, you can change the name of the enum type in case a need arises by following the steps below:
Find the enum data types applied to your
products
table by running a describe (\d
) table command.company_db=> \d products;
Note the enum type names under the
Type
column in the following output.Column | Type | Collation | Nullable | Default --------------+-----------------------+-----------+----------+---------------------------------------------- product_id | integer | | not null | nextval('products_product_id_seq'::regclass) product_name | character varying(50) | | | sku | character varying(50) | | | product_type | product_type_enum | | | availability | availability_enum | | | retail_price | double precision | | | Indexes: "products_pkey" PRIMARY KEY, btree (product_id)
Run the following command to change the enum type name from
product_type_enum
totype_of_product_enum
.company_db=> ALTER TYPE product_type_enum RENAME TO type_of_product_enum;
Output.
ALTER TYPE
Review the structure of the
products
table again to confirm the changes.company_db=> \d products;
You've successfully changed the name of the
product_type_enum
totype_of_product_enum
.Column | Type | Collation | Nullable | Default --------------+-----------------------+-----------+----------+---------------------------------------------- product_id | integer | | not null | nextval('products_product_id_seq'::regclass) product_name | character varying(50) | | | sku | character varying(50) | | | product_type | type_of_product_enum | | | availability | availability_enum | | | retail_price | double precision | | | Indexes: "products_pkey" PRIMARY KEY, btree (product_id)
5.2. Add a New Value to An Existing Enum Data Type
To add a new value to an existing enum data type, use the syntax below.
=> ALTER TYPE SAMPLE_TYPE ADD VALUE 'SAMPLE_ENUM_VALUE';
Add a new
DOWNLOAD
value to thetype_of_product_enum
.company_db=# ALTER TYPE type_of_product_enum ADD VALUE 'DOWNLOAD';
Output.
ALTER TYPE
List
product_type_enum
values to verify the change.company_db=> SELECT UNNEST(enum_range(null::type_of_product_enum)) AS type_of_product_enum;
Output.
type_of_product_enum ---------------- PHYSICAL NON-PHYSICAL DOWNLOAD (3 rows)
Specify the sort position when adding new enum type values in an existing list using the
BEFORE
orAFTER
keywords as shown below.company_db=> ALTER TYPE type_of_product_enum ADD VALUE 'CONSUMABLE' AFTER 'PHYSICAL'; ALTER TYPE type_of_product_enum ADD VALUE 'EXPLOSIVES' BEFORE 'DOWNLOAD';
Output.
... ALTER TYPE
Verify the changes.
company_db=> SELECT UNNEST(enum_range(null::type_of_product_enum)) AS type_of_product_enum;
Output.
type_of_product_enum ------------------- PHYSICAL CONSUMABLE NON-PHYSICAL EXPLOSIVES DOWNLOAD (5 rows)
5.3. Rename Enum Type Value
To rename an existing enum data type value, use the following syntax.
=> ALTER TYPE SAMPLE_TYPE ADD VALUE 'SAMPLE_ENUM_VALUE';
To change the 'DOWNLOAD' value to 'SOFTWARE DOWNLOAD' in the
type_of_product_enum
data type, run the following command.company_db=> ALTER TYPE type_of_product_enum RENAME VALUE 'DOWNLOAD' TO 'SOFTWARE DOWNLOAD';
Output.
ALTER TYPE
Verify the changes.
company_db=> SELECT UNNEST(enum_range(null::type_of_product_enum)) AS type_of_product_enum;
Output.
type_of_product_enum ------------------- PHYSICAL CONSUMABLE NON-PHYSICAL EXPLOSIVES SOFTWARE DOWNLOAD (5 rows)
5.4. Change Enum Type Sort Order and Delete Values
PostgreSQL doesn't allow you to change the sort order or delete enum type values from an existing list. The only workaround is dropping and creating the enum type. For instance, to rearrange the sort order of the availability_enum
data type from ONLINE, STOREFRONT, BOTH
to BOTH, ONLINE, STOREFRONT
, follow the steps below:
Verify the active sort order from the
availability_enum
data type.company_db=# SELECT UNNEST(enum_range(null::availability_enum)) AS availability_enum;
Output.
availability_enum ------------------- ONLINE STOREFRONT BOTH (3 rows)
Rename the active enum data type to a new name. You can use the
_old
suffix at the end of the enum type name to avoid confusion.company_db=# ALTER TYPE availability_enum RENAME TO availability_enum_old;
Output.
ALTER TYPE
Recreate a new
availability_enum
data type with your new order.company_db=# CREATE TYPE availability_enum AS ENUM ('BOTH', 'ONLINE', 'STOREFRONT');
Output.
CREATE TYPE
Map the new enum data type to the
products
table by casting theavailability
column text values to the newavailability_enum
data type.company_db=# ALTER TABLE products ALTER COLUMN availability TYPE availability_enum USING availability::text::availability_enum;
Output.
ALTER TABLE
Delete the old (
availability_enum_old
) enum data type.company_db=> DROP TYPE availability_enum_old;
Output.
DROP TYPE
Query the
availability_enum
data type to ensure the new sort order reflects your desired output.company_db=# SELECT UNNEST(enum_range(null::availability_enum)) AS availability_enum;
Output.
availability_enum ------------------- BOTH ONLINE STOREFRONT (3 rows)
Conclusion
This guide shows you how to use a managed PostgreSQL database server enumerated data types on Ubuntu 20.04. In this guide, you have created a sample database, declared two custom enum data types, and applied them to a products
table. You've also run some commands to insert data into the enum columns. Towards the end, you've learned how to add and rearrange the enum data type values.
Check out the following links to learn more about Vultr's managed databases: