Ответ 1
Пока вы не можете использовать enum для integer в качестве объяснения 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
notIMMUTABLE
, потому что добавление (или добавление поддержки в Pg позже добавляется, удаление) значений из перечислений изменяет индексы упорядочения и разрыва, основанные на упорядочении; поэтому - Вы не можете использовать это в выражении индекса; и
- It
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)
Обратите внимание, что это, наверное, безумная вещь, не поддерживается, и, вполне вероятно, это ужасная идея. Ваш код должен знать, что порядковые значения будут меняться при добавлении или (если позже будут поддерживаться) удалите значение из перечисления.
Индексы, созданные на основе этого приведения (возможно только в том случае, если функция определена неизменяемой) начнут производить безумные и неправильные результаты, если вы измените определение перечисления (за исключением добавления новых значений до конца), поскольку PostgreSQL полагает, что вы когда вы говорите, что функция неизменна. Не делайте этого.