能否将枚举转换为整数?从第一个元素开始编号为1。
正如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
,因为它应该对空输入返回null现在您可以使用此函数为特定的枚举类型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)
如果您愿意使用函数enum_range()并对其结果进行计数,您就可以完成此操作。
如果将枚举值作为enum_range()函数的第二个参数传递,NULL作为第一个参数,则会得到一个包含该点之前枚举可以采用的所有值的数组。然后您只需要使用array_length计算它们的数量,即可获得表示枚举的整数。
这是一个例子。这是我的枚举:
content=# select enum_range(null::content_state);
enum_range
--------------------------------------------------------------
{created,deleted,preview,draft,submitted,approved,published}
这是我算出“draft”值的整数:
content=# select array_length(enum_range(NULL, 'draft'::content_state), 1);
array_length
--------------
4
注意:从枚举中删除值将使您的整数指向其他值,因此不要在可能需要更改的枚举上使用此功能。
我有一个枚举类型,需要用 FK(int4)替换它。以下方法适合我:
ALTER TABLE public."superhero"
ALTER COLUMN "power" TYPE int4
USING "power"::text::int4;