是否可以将枚举转换为整数?从1开始第一个元素
答案 0 :(得分:24)
虽然您不能像Catcall解释的那样将枚举转换为整数,但您可以使用PostgreSQL特定的,可能不是版本兼容版本的pg_enum
系统目录表来获取一个序数表示。
regress=# CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
regress=# select enumsortorder, enumlabel from pg_catalog.pg_enum
regress-# WHERE enumtypid = 'happiness'::regtype ORDER BY enumsortorder;
enumsortorder | enumlabel
---------------+------------
1 | happy
2 | very happy
3 | ecstatic
(3 rows)
这看起来很简单,但事实并非如此。观察:
regress=# ALTER TYPE happiness ADD VALUE 'sad' BEFORE 'happy';
regress=# ALTER TYPE happiness ADD VALUE 'miserable' BEFORE 'very happy';
regress=# SELECT * FROM pg_enum ;
enumtypid | enumsortorder | enumlabel
-----------+---------------+------------
185300 | 1 | happy
185300 | 2 | very happy
185300 | 3 | ecstatic
185300 | 0 | sad
185300 | 1.5 | miserable
(5 rows)
从中您可以看到enumsortorder
提供了排序,但没有固定的“距离”。如果添加了从枚举中删除值的支持,它也可能会在序列中创建“漏洞”。
要获得枚举位置,您需要使用row_number()
窗口函数来获取排序,并使用pg_typeof
获取oid
(regtype
)枚举类型。当有多个具有相同标签的枚举时,您需要这样做以确保返回正确的序号。
此功能完成工作:
CREATE OR REPLACE FUNCTION enum_to_position(anyenum) RETURNS integer AS $$
SELECT enumpos::integer FROM (
SELECT row_number() OVER (order by enumsortorder) AS enumpos,
enumsortorder,
enumlabel
FROM pg_catalog.pg_enum
WHERE enumtypid = pg_typeof($1)
) enum_ordering
WHERE enumlabel = ($1::text);
$$ LANGUAGE 'SQL' STABLE STRICT;
注意:
STABLE
而不是IMMUTABLE
,因为从枚举中添加(或者如果稍后添加Pg中的支持,删除)值会更改依赖于排序的排序和中断索引;所以STRICT
,因为它应该为空输入现在,您可以将此功能用于CREATE CAST
,以获取integer
的特定枚举。您无法为integer
的所有枚举创建通用转换,因为anyenum
伪类型不能用于强制转换。例如,如果我想允许将演示happiness
强制转换为整数,我会写:
CREATE CAST (happiness AS integer) WITH FUNCTION enum_to_position(anyenum);
之后我可以成功执行:
regress=# SELECT ('happy'::happiness)::integer;
int4
------
2
(1 row)
请注意,这可能是疯狂的要做的事情,不受支持,并且很可能是一个糟糕的主意。您的代码必须注意,当您添加或(如果以后支持)从枚举中删除值时,序号值将更改。
基于此强制转换创建的索引(仅当函数定义为不可变时才可能)如果更改枚举的定义(除了通过在其末尾添加新值),将开始产生疯狂和错误的结果,因为PostgreSQL相信你当你说一个函数是不可变的。不要那样做。
答案 1 :(得分:17)
您可以通过巧妙滥用函数enum_range()来实现此目的。
如果您将枚举值作为enum_range()函数的第二个参数传递,并且NULL是第一个,那么您将得到一个数组,其中包含enum可以占用的所有值。然后你只需要用array_length来计算它们,你就得到一个代表枚举的整数。
这是一个例子。这是我的枚举:
content=# select enum_range(null::content_state);
enum_range
--------------------------------------------------------------
{created,deleted,preview,draft,submitted,approved,published}
这就是我找出“草稿”值的int:
content=# select array_length(enum_range(NULL, 'draft'::content_state), 1);
array_length
--------------
4
警告:从枚举中删除值会使您的整数指向其他值,因此请勿在您可能希望在某些时候更改的枚举上使用此值。
答案 2 :(得分:3)
您无法将枚举转换为整数。
你可能能够写一个custom operator来提取与某个值相关联的数字,但我发现很难相信这是值得的。
如果我需要那种信息,我已经构建了一个表并设置了一个外键引用,而不是使用枚举。