我有一个使用枚举类型的表列。我希望更新枚举类型有一个额外的可能值。我不想删除任何现有的值,只是添加新的值。最简单的方法是什么?


当前回答

如上所述,ALTER命令不能写入事务内部。建议的方法是直接插入到pg_enum表中,从pg_type表中检索typelem并计算下一个enumsortorder号;

以下是我使用的代码。检查插入前是否存在重复值(enumtypid和enumlabel名称之间的约束)

INSERT INTO pg_enum (enumtypid, enumlabel, enumsortorder)
    SELECT typelem,
    'NEW_ENUM_VALUE',
    (SELECT MAX(enumsortorder) + 1 
        FROM pg_enum e
        JOIN pg_type p
        ON p.typelem = e.enumtypid
        WHERE p.typname = '_mytypename'
    )
    FROM pg_type p
    WHERE p.typname = '_mytypename'
    AND NOT EXISTS (
        SELECT * FROM 
        pg_enum e
        JOIN pg_type p
        ON p.typelem = e.enumtypid
        WHERE e.enumlabel = 'NEW_ENUM_VALUE'
        AND p.typname = '_mytypename'
    )

注意,在pg_type表中,类型名前面有下划线。此外,where子句中的typname必须全部小写。

现在这可以安全地写入您的db migrate脚本。

其他回答

最简单的方法:去掉枚举。它们不容易修改,因此应该很少使用。

免责声明:我没有尝试过这个解决方案,所以它可能不起作用;-)

您应该查看pg_enum。如果你只想改变一个现有ENUM的标签,一个简单的UPDATE就可以做到。

添加一个新的ENUM值。

首先将新值插入到pg_enum中。如果新值必须是最后一个,那么就完成了。 如果不是(你需要一个新的ENUM值在现有的值之间),你将不得不更新你的表中每个不同的值,从最高到最低… 然后你只需要在pg_enum中以相反的顺序重命名它们。

插图 您有以下一组标签:

ENUM ('enum1', 'enum2', 'enum3')

你想要得到:

ENUM ('enum1', 'enum1b', 'enum2', 'enum3')

然后:

INSERT INTO pg_enum (OID, 'newenum3');
UPDATE TABLE SET enumvalue TO 'newenum3' WHERE enumvalue='enum3';
UPDATE TABLE SET enumvalue TO 'enum3' WHERE enumvalue='enum2';

然后:

UPDATE TABLE pg_enum SET name='enum1b' WHERE name='enum2' AND enumtypid=OID;

等等……

注意:如果你正在使用PostgreSQL 9.1或更高版本,并且你可以在事务之外进行更改,请参阅下面的回答,以获得更简单的方法。


几天前我也遇到了同样的问题,发现了这个帖子。所以我的回答可以帮助那些正在寻找解决方案的人:)

如果只有一两个列使用想要更改的枚举类型,可以尝试这样做。此外,您还可以更改新类型中值的顺序。

-- 1. rename the enum type you want to change
alter type some_enum_type rename to _some_enum_type;
-- 2. create new type
create type some_enum_type as enum ('old', 'values', 'and', 'new', 'ones');
-- 3. rename column(s) which uses our enum type
alter table some_table rename column some_column to _some_column;
-- 4. add new column of new type
alter table some_table add some_column some_enum_type not null default 'new';
-- 5. copy values to the new column
update some_table set some_column = _some_column::text::some_enum_type;
-- 6. remove old column and type
alter table some_table drop column _some_column;
drop type _some_enum_type;

如有多于一栏,应重复3-6。

PostgreSQL 9.1引入了ALTER Enum类型的功能:

ALTER TYPE enum_type ADD VALUE 'new_value'; -- appends to list
ALTER TYPE enum_type ADD VALUE 'new_value' BEFORE 'old_value';
ALTER TYPE enum_type ADD VALUE 'new_value' AFTER 'old_value';

如果你正在使用Postgres 12(或更高版本),你可以运行ALTER TYPE…在交易(文档)中增加价值。

如果ALTER TYPE…ADD VALUE(向枚举中添加新值的表单 类型)在事务块内执行,则新值不能为 一直使用到事务提交之后。

因此在迁移中不需要任何hack。

UPD:这里有一个例子(感谢Nick)

添加一个新值