Postgres中的代数数据类型

时间:2017-06-08 09:26:27

标签: sql postgresql types enums union-types

是否可以在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&#em>下面的回复确实允许我创建一个产品类型,但它仍然不允许我根据需要创建一个联合类型。

4 个答案:

答案 0 :(得分:6)

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

您可以创建类似于:

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

使用示例:

CREATE TABLE your_table
(
    a ANIMAL
);

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

答案 1 :(得分:2)

使用功能:

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)

答案 2 :(得分:1)

实际上,您正在尝试合并两种enum类型 有一些悬而未决的问题:

  • 可以有重复的字符串吗?
  • 设计应该是静态(对enum类型hoofed的更改不会在以后更改类型animal)或动态(相反)。< / LI>
  • 合并两种enum种类型或更多?
  • 由于元素的顺序很重要,animal中元素的顺序是什么?
  • 这是一次性操作还是打算重复使用?

假设 没有重复项,静态设计,两种enum类型,附加元素的现有顺序以及一次性操作。

您可以使用内置enum support function 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
$$;

答案 3 :(得分:1)

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

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

注意:但是,对于DOMAIN类型,您将失去ENUM属性:自定义排序。 DOMAIN将始终使用基础类型的排序。