PostgreSQL 9.0 和 9.1 之间枚举类型文字的排序差异

Luk*_*der 4 sql postgresql jooq postgresql-9.0 postgresql-9.1

enum类型在 PostgreSQL 9.0 和 9.1 之间的工作方式发生了一些奇怪的更新。该pg_catalog.pg_enumenumsortorder在 PostgreSQL 9.1中有一个新列。这个顺序似乎覆盖了之前基于 OID 的枚举顺序。

PostgreSQL 9.0 文档

特定枚举类型的 OID 保证按类型排序的方式排序,但不保证无关枚举类型的 OID 的排序。

PostgreSQL 9.1 文档

pg_enum 行的 OID 遵循一个特殊规则:保证偶数 OID 的排序方式与其枚举类型的排序顺序相同。也就是说,如果两个偶数 OID 属于同一枚举类型,则较小的 OID 必须具有较小的 enumsortorder 值。奇数 OID 值与排序顺序无关。此规则允许枚举比较例程在许多常见情况下避免目录查找。创建和更改枚举类型的例程尝试尽可能将 OID 分配给枚举值。

创建枚举类型时,其成员被分配排序顺序位置 1..n。但是后来添加的成员可能会被赋予 enumsortorder 的负值或小数值。对这些值的唯一要求是它们在每个枚举类型中正确排序和唯一。

我的问题

对于jOOQ 代码生成器,我正在阅读pg_catalog.pg_enum表,按 OID 对枚举文字进行排序,这是在 PostgreSQL 9.0 中指定的方式。使用 udpated 规范,似乎我应该按 对文字进行排序enumsortorder,它的行为似乎有所不同,因为它尊重“中间”的枚举文字插入。

pg_catalog.

Cra*_*ger 5

我认为您需要检查 PostgreSQL 版本并适当更改行为,或者使用不涉及目录的 SQL 来确定排序。

给定虚拟枚举,后者的想法:

CREATE TYPE test_enum AS ENUM ('z','x','y');
ALTER TYPE test_enum ADD VALUE 'a' BEFORE 'x';
Run Code Online (Sandbox Code Playgroud)

ORDER BY使用row_number8.4 和更新版本中可用的窗口函数将枚举标签转换为枚举类型的值:

SELECT enumlabel, row_number() OVER (ORDER BY enumlabel::test_enum) AS sort_key
FROM pg_catalog.pg_enum
WHERE enumtypid = 'test_enum'::regtype;
Run Code Online (Sandbox Code Playgroud)

这将为您提供按排序键排序的标签。在较旧的 Pg 版本中,Pg 将仅按oid枚举值排序,在较新的版本中它将使用 enumsortorder,但您不必关心任何一种方式,您只是告诉 PostgreSQL“请按正确的顺序将它们排序”。

或者,如果您只是按照服务器期望的顺序需要它们,请编写:

SELECT enumlabel
FROM pg_catalog.pg_enum
WHERE enumtypid = 'test_enum'::regtype
ORDER BY enumlabel::test_enum
Run Code Online (Sandbox Code Playgroud)