Postgres中的代数数据类型



是否可以在Postgres中创建代数数据类型,然后将其用作列类型?

例如:

CREATE TYPE hoofed AS ENUM('horse', 'goat');
CREATE TYPE monkey AS ENUM('chimp','macaque');
CREATE TYPE ANIMAL AS ENUM(hoofed, monkey);

这失败了:

syntax error at or near "hoofed"
LINE 1: CREATE TYPE ANIMAL AS ENUM(hoofed, monkey);

可以做这样的事情吗?

最终我想做的是这样的事情:

CREATE TABLE zoo (
    a ANIMAL,
    name text
);
INSERT INTO zoo(a, name) VALUES('horse', 'bob');
INSERT INTO zoo(a, name) VALUES('macaque', 'jimmy');

以及两个记录都具有独立有效。

编辑: @abihabi87的响应下面 do 允许我实际上创建一种产品类型,但它仍然不允许我根据需要创建一个联合类型。

您无法从其他枚举类型中创建类型的枚举:

您可以创建喜欢:

的动物
CREATE TYPE ANIMAL AS (h hoofed,m monkey);

使用的示例:

CREATE TABLE your_table
(
    a ANIMAL
);
INSERT INTO your_table(a) select (select ('horse','macaque')::ANIMAL);

使用ENUM类型,您无法实现动态类型组成/联合。但是,使用DOMAIN类型,您可以实现类似的目标:

create function valid_any_domain(anyelement, variadic regtype[])
  returns boolean
  language plpgsql
  immutable
as $func$
declare
  t regtype;
begin
  foreach t in array $2 loop
    begin
      execute format('select $1::%s', t) using $1;
    exception
      when not_null_violation or check_violation then
        continue;
    end;
    return true;
  end loop;
  return false;
end;
$func$;
create domain hoofed as text
  check (value in ('horse', 'goat'));
create domain monkey as text
  check (value in ('chimp','macaque'));
create domain animal as text
  check (valid_any_domain(value, 'hoofed', 'monkey'));

更改基本类型也将动态更改复合/联合类型,但仍需要手动约束验证(尤其是当从有效频谱中删除某些值时(:

alter domain hoofed drop constraint hoofed_check;
alter domain hoofed add check (value in ('horse', 'goat', 'zebra'));
alter domain animal validate constraint animal_check;

http://rextester.com/mbvc62095

Note :但是,使用DOMAIN类型,您将丢失ENUM属性:自定义订购。DOMAIN S将始终使用基础类型的订购。

使用函数:

create or replace function create_enum(name, variadic regtype[])
returns void language plpgsql as $$
begin
    execute format(
        'create type %I as enum(%s)', 
        $1, 
        string_agg(quote_literal(enumlabel), ',' order by enumtypid, enumsortorder))
    from pg_enum
    where enumtypid = any($2);
end $$;

将新类型的名称和枚举类型的列表作为参数:

select create_enum('animal', 'hoofed', 'monkey');
select enum_range(null::animal) as animal;
           animal           
----------------------------
 {horse,goat,chimp,macaque}
(1 row)

有效地尝试合并两种enum类型。
有一些开放的问题:

  • 可以有重复的字符串吗?
  • 设计是 static (更改为 enum类型hoofed请勿更改type type animal(或Dynamic(相反(。
  • 完全合并两种enum类型或更多?
  • 由于元素的顺序很重要,因此animal中的元素顺序应该是多少?
  • 这是一次性操作还是打算重复使用?

假设 无重复,静态设计,两种enum类型,现有的元素顺序和一次性操作。

您可以使用内置枚举支持功能enum_range(anyenum)获取给定enum类型的所有元素的数组。

DO
$$
BEGIN
EXECUTE (
   SELECT 'CREATE TYPE animal AS ENUM (' 
        || array_to_string(enum_range(null::hoofed)::text[]
                        || enum_range(null::monkey)::text[], ''',''')
        || ''')'
   );
END
$$;

最新更新