我有一个使用枚举类型的表列。我希望更新枚举类型有一个额外的可能值。我不想删除任何现有的值,只是添加新的值。最简单的方法是什么?
当前回答
我不知道是否有其他选择,但我们可以使用:
select oid from pg_type where typname = 'fase';'
select * from pg_enum where enumtypid = 24773;'
select * from pg_enum where enumtypid = 24773 and enumsortorder = 6;
delete from pg_enum where enumtypid = 24773 and enumsortorder = 6;
其他回答
DB::statement("ALTER TABLE users DROP CONSTRAINT users_user_type_check");
$types = ['old_type1', 'old_type1', 'new_type3'];
$result = join( ', ', array_map(function ($value){
return sprintf("'%s'::character varying", $value);
}, $types));
DB::statement("ALTER TABLE users ADD CONSTRAINT users_user_type_check CHECK (user_type::text = ANY (ARRAY[$result]::text[]))");
补充@Dariusz 1
对于Rails 4.2.1,有这样的文档部分:
==事务性迁移
如果数据库适配器支持DDL事务,则所有迁移都将支持 自动包装在事务中。有一些查询 但是不能在事务中执行,对于这些情况 您可以关闭自动事务处理。
class ChangeEnum < ActiveRecord::Migration
disable_ddl_transaction!
def up
execute "ALTER TYPE model_size ADD VALUE 'new_value'"
end
end
更新pg_enum可以工作,就像上面突出显示的中间列技巧一样。你也可以使用USING魔法直接改变列的类型:
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;
只要没有函数显式地要求或返回该枚举,就没问题。(如果有,pgsql会在删除类型时报错。)
另外,请注意PG9.1引入了一个ALTER TYPE语句,它将对枚举起作用:
http://developer.postgresql.org/pgdocs/postgres/release-9-1-alpha.html
如上所述,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脚本。
注意:如果你正在使用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。
推荐文章
- 查询JSON类型内的数组元素
- 获得PostgreSQL数据库中当前连接数的正确查询
- MySQL数据库表中的最大记录数
- 我可以在Java中设置enum起始值吗?
- 从现有模式生成表关系图(SQL Server)
- HyperLogLog算法是如何工作的?
- 纬度和经度的数据类型是什么?
- 数据库和模式的区别
- 如何在PostgreSQL中临时禁用触发器?
- c# vs Java Enum(适合c#新手)
- 输入文件似乎是一个文本格式转储。请使用psql
- 使用LIMIT/OFFSET运行查询,还可以获得总行数
- 当恢复sql时,psql无效命令\N
- 如何从命令行在windows中找到mysql数据目录
- 货币应该使用哪种数据类型?