PostgreSQL技术问答08 - ENUM
本文是《PostgreSQL技术问答》系列文章中的一篇。关于这个系列的由来,可以参阅开篇文章:
文章的编号只是一个标识,在系列中没有明确的逻辑顺序和意义。读者进行阅读时,不用太关注这个方面。
本文笔者想要来讨论一下在PostgreSQL中的ENUM,即枚举这一功能和特性。
什么是ENUM枚举
ENUM在编程语言中,是一个非常常见的概念。通常而言,ENUM即枚举,它是一个数据集合,这个集合中的元素是有限,有序、并且相对固定的,并作为一种特殊的数据类型。要使用这个数据类型,就只能使用这个集合中的某个元素。
ENUM的作用和好处在于:
- 数据完整性: 使用ENUM可以确保数据只能是预定义的值,减少创建和使用无效数据的风险
- 可读性: 枚举可以使数据更加可读,因为它通常使用一个字符串标签来描述数据的值,具有自解释性
- 性能: 通常情况下,系统实际使用更简单的数据类型(如整数)来映射和实现枚举,相关处理更加高效
- 有序:定义枚举值时,需要指定顺序,可以天然的作为排序的依据
一个常见的应用场景就是用户的性别,可以定义一个性别的枚举类型,只有“男”和“女”两种,使用时只能在两种中选择其一,保证了不会用到无效或者错误的数据,同时也保证了程序的可读性和容易理解。
笔者认为,在Postgres中,这个概念和实现,包括其设计的目的,其实也是类似的。笔者甚至觉得,在PG中,ENUM就是一个整数,但使用一个字符串标签,方便人类理解和使用。
这里顺便提一下,在JS中,其实是没有原生的枚举数据类型的,通常只能通过对象常量、符号等技术手段来实现和模拟。
PG中如何创建和使用枚举
下面的代码,展示了PG定义和使用ENUM的一般流程:
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
CREATE TABLE person (
name text,
current_mood mood
);
INSERT INTO person VALUES ('Moe', 'happy');
SELECT * FROM person WHERE current_mood = 'happy';
name | current_mood
------+--------------
Moe | happy
(1 row)
这段示例代码我们可以看到:
- ENUM是一种特殊的数据类型,可以使用数据类型定义的方式创建
- ENUM的定义内容是一个字符串序列
- 使用时,需要声明表字段类型为定义好的ENUM类型
- 使用ENUM的方式,基本上和字符串是相同的,但这个字符串,被限制在ENUM定义的内容当中
如何修改ENUM
虽然这个操作是不建议的,因为枚举类型是相对固定的内容,最好在应用开发时进行很好的规划和设置。但Postgres支持对ENUM的定义和内容进行一定程度的修改。相关的操作通常使用Alter Type语句完成,下面是一些示例:
// 创建枚举
CREATE TYPE 角色 AS ENUM ('嘉宾', '主持人', '观众');
// 增加枚举值
ALTER TYPE 角色 ADD VALUE '志愿者';
// 修改枚举值
ALTER TYPE 角色 RENAME VALUE '主持人' TO '主持';
// 检查枚举
SELECT n.nspname AS schema, t.typname AS enum_type, e.enumlabel AS 值
FROM pg_type t
JOIN pg_enum e ON t.oid = e.enumtypid
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
ORDER BY
n.nspname, t.typname, e.enumsortorder;
关于ENUM有什么需要注意的问题
关于在PG中使用ENUM需要注意的问题,这里简单总结一下:
- ENUM本身是有序的,项目的排序,就是其在定义时的次序
- ENUM标签是区分大小写的
- 虽然看起来都是字符串,但不同的ENUM之间不能直接进行比较(用于关联或者排序),如果确实要这样做,可能需要先进行类型转换
- 对ENUM修改需要注意对当前数据的影响
- ENUM不支持直接的值的删除或者重新排序,如果确实要这么做,可以考虑使用临时数据表来进行操作
- PG也没有提供非常简单的枚举定义查询的方式,现在一般通过查询系统表来实现
小结
本文讨论了Postgres中的一种特殊的数据类型:ENUM,即枚举型。包括了它的定义、使用场景,在Postgres中的一般的操作方式,和一些相关的限制,以及需要注意的问题。
转载自:https://juejin.cn/post/7375810931098894399