Ian*_*Ian 178 database postgresql enums
我有一个使用enum
类型的表列.我希望更新该enum
类型以获得额外的可能值.我不想删除任何现有值,只需添加新值.最简单的方法是什么?
Dar*_*usz 356
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';
Run Code Online (Sandbox Code Playgroud)
小智 137
注意如果您使用的是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;
Run Code Online (Sandbox Code Playgroud)
如果有超过1列,则应重复3-6.
小智 62
可能的解决方案如下:前提条件是,使用的枚举值中没有冲突.(例如,在删除枚举值时,请确保不再使用此值.)
-- rename the old enum
alter type my_enum rename to my_enum__;
-- create the new enum
create type my_enum as enum ('value1', 'value2', 'value3');
-- alter all you enum columns
alter table my_table
alter column my_column type my_enum using my_column::text::my_enum;
-- drop the old enum
drop type my_enum__;
Run Code Online (Sandbox Code Playgroud)
同样以这种方式不会更改列顺序.
Hub*_*tus 28
如果您遇到应enum
在事务中添加值的情况,请在flyway migration on ALTER TYPE
statement中执行它,您将收到错误ERROR: ALTER TYPE ... ADD cannot run inside a transaction block
(请参阅flyway问题#350)您可以pg_enum
直接将这些值添加到变通方法(type_egais_units
是目标名称enum
):
INSERT INTO pg_enum (enumtypid, enumlabel, enumsortorder)
SELECT 'type_egais_units'::regtype::oid, 'NEW_ENUM_VALUE', ( SELECT MAX(enumsortorder) + 1 FROM pg_enum WHERE enumtypid = 'type_egais_units'::regtype )
Run Code Online (Sandbox Code Playgroud)
小智 18
补充@Dariusz 1
对于Rails 4.2.1,有这个doc部分:
==交易迁移
如果数据库适配器支持DDL事务,则所有迁移将自动包装在事务中.但是有些查询无法在事务中执行,并且在这些情况下,您可以关闭自动事务.
class ChangeEnum < ActiveRecord::Migration
disable_ddl_transaction!
def up
execute "ALTER TYPE model_size ADD VALUE 'new_value'"
end
end
Run Code Online (Sandbox Code Playgroud)
Lev*_*sov 18
如果您使用的是 Postgres 12(或更高版本),您可以ALTER TYPE ... ADD VALUE
在事务内部运行(文档)。
如果在事务块内执行 ALTER TYPE ... ADD VALUE(向枚举类型添加新值的形式),则在提交事务之前不能使用新值。
所以在迁移中不需要黑客。
UPD:这是一个例子(感谢尼克)
ALTER TYPE enum_type ADD VALUE 'new_value';
Pey*_*nkh 10
来自Postgres 9.1 文档:
ALTER TYPE name ADD VALUE new_enum_value [ { BEFORE | AFTER } existing_enum_value ]
Run Code Online (Sandbox Code Playgroud)
例:
ALTER TYPE user_status ADD VALUE 'PROVISIONAL' AFTER 'NORMAL'
Run Code Online (Sandbox Code Playgroud)
小智 7
免责声明:我没有尝试过这个解决方案,所以它可能无法正常工作;-)
你应该看看pg_enum
.如果您只想更改现有ENUM的标签,则可以使用简单的UPDATE.
要添加新的ENUM值:
pg_enum
.如果新值必须是最后一个,那么你就完成了.pg_enum
相反的顺序重命名它们.插图
您有以下标签集:
ENUM ('enum1', 'enum2', 'enum3')
Run Code Online (Sandbox Code Playgroud)
而你想获得:
ENUM ('enum1', 'enum1b', 'enum2', 'enum3')
Run Code Online (Sandbox Code Playgroud)
然后:
INSERT INTO pg_enum (OID, 'newenum3');
UPDATE TABLE SET enumvalue TO 'newenum3' WHERE enumvalue='enum3';
UPDATE TABLE SET enumvalue TO 'enum3' WHERE enumvalue='enum2';
Run Code Online (Sandbox Code Playgroud)
然后:
UPDATE TABLE pg_enum SET name='enum1b' WHERE name='enum2' AND enumtypid=OID;
Run Code Online (Sandbox Code Playgroud)
等等...
以防万一,如果您使用的是 Rails 并且有多个语句,则需要一一执行,例如:
execute "ALTER TYPE XXX ADD VALUE IF NOT EXISTS 'YYY';"
execute "ALTER TYPE XXX ADD VALUE IF NOT EXISTS 'ZZZ';"
Run Code Online (Sandbox Code Playgroud)
小智 6
无法将注释添加到适当的位置,但ALTER TABLE foo ALTER COLUMN bar TYPE new_enum_type USING bar::text::new_enum_type
在列上使用默认值失败。我不得不:
ALTER table ALTER COLUMN bar DROP DEFAULT
;
然后就成功了。
我似乎无法发表评论,所以我只是说更新pg_enum适用于Postgres 8.4.对于我们的枚举设置方式,我通过以下方式为现有枚举类型添加了新值:
INSERT INTO pg_enum (enumtypid, enumlabel)
SELECT typelem, 'NEWENUM' FROM pg_type WHERE
typname = '_ENUMNAME_WITH_LEADING_UNDERSCORE';
Run Code Online (Sandbox Code Playgroud)
这有点可怕,但鉴于Postgres实际存储数据的方式,这是有道理的.
更新pg_enum的工作原理与上面突出显示的中间列技巧一样.也可以使用USING magic直接更改列的类型:
CREATE TYPE test AS enum('a', 'b');
CREATE TABLE foo (bar test);
INSERT INTO foo VALUES ('a'), ('b');
ALTER TABLE foo ALTER COLUMN bar TYPE varchar;
DROP TYPE test;
CREATE TYPE test as enum('a', 'b', 'c');
ALTER TABLE foo ALTER COLUMN bar TYPE test
USING CASE
WHEN bar = ANY (enum_range(null::test)::varchar[])
THEN bar::test
WHEN bar = ANY ('{convert, these, values}'::varchar[])
THEN 'c'::test
ELSE NULL
END;
Run Code Online (Sandbox Code Playgroud)
只要你没有明确要求或返回枚举的函数,你就会很好.(如果丢弃类型,pgsql会抱怨.)
另请注意,PG9.1引入了一个ALTER TYPE语句,该语句适用于枚举:
http://developer.postgresql.org/pgdocs/postgres/release-9-1-alpha.html
归档时间: |
|
查看次数: |
95112 次 |
最近记录: |