Eu tenho uma coluna da tabela que usa um enum
tipo. Desejo atualizar esse enum
tipo para ter um valor adicional possível. Não quero excluir nenhum valor existente, basta adicionar o novo valor. Qual é a maneira mais simples de fazer isso?
fonte
Eu tenho uma coluna da tabela que usa um enum
tipo. Desejo atualizar esse enum
tipo para ter um valor adicional possível. Não quero excluir nenhum valor existente, basta adicionar o novo valor. Qual é a maneira mais simples de fazer isso?
OBSERVAÇÃO Se você estiver usando o PostgreSQL 9.1 ou posterior, e está autorizado a fazer alterações fora de uma transação, consulte esta resposta para uma abordagem mais simples.
Eu tive o mesmo problema há alguns dias e encontrei este post. Portanto, minha resposta pode ser útil para alguém que está procurando solução :)
Se você tiver apenas uma ou duas colunas que usam o tipo de enumeração que deseja alterar, tente isso. Além disso, você pode alterar a ordem dos valores no novo tipo.
-- 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 deve ser repetido se houver mais de uma coluna.
ALTER TYPE
. Mas mesmo antes disso,ALTER TABLE foo ALTER COLUMN bar TYPE new_type USING bar::text::new_type;
era muito superior.ALTER TABLE some_table ALTER COLUMN some_column TYPE some_enum_type USING some_column::text::some_enum_type;
O PostgreSQL 9.1 introduz a capacidade dos tipos ALTER Enum:
fonte
Uma solução possível é a seguinte; pré-condição é que não haja conflitos nos valores de enum usados. (por exemplo, ao remover um valor de enumeração, verifique se esse valor não é mais usado.)
Além disso, a ordem das colunas não será alterada.
fonte
pg_enum
que podem realmente quebrar as coisas e são transacionais, ao contrárioALTER TYPE ... ADD
.default for column "my_column" cannot be cast automatically to type "my_enum"
. Você deverá fazer o seguinte:ALTER TABLE "my_table" ALTER COLUMN "my_column" DROP DEFAULT, ALTER COLUMN "my_column" TYPE "my_type" USING ("my_column"::text::"my_type"), ALTER COLUMN "my_column" SET DEFAULT 'my_default_value';
Se você se enquadra na situação em que deve adicionar
enum
valores na transação, executá-lo na migração flyway naALTER TYPE
instrução, você receberá um erroERROR: ALTER TYPE ... ADD cannot run inside a transaction block
(consulte o número de flyway nº 350 ). Você pode adicionar esses valorespg_enum
diretamente como solução alternativa (type_egais_units
é o nome do destinoenum
):fonte
Complementando @Dariusz 1
Para o Rails 4.2.1, há esta seção de documento:
== Migrações transacionais
Se o adaptador de banco de dados suportar transações DDL, todas as migrações serão agrupadas automaticamente em uma transação. Existem consultas que você não pode executar dentro de uma transação e, para essas situações, pode desativar as transações automáticas.
fonte
Da documentação do Postgres 9.1 :
Exemplo:
fonte
Disclaimer: Eu não tentei esta solução, por isso pode não funcionar ;-)
Você deveria estar olhando
pg_enum
. Se você deseja alterar apenas o rótulo de um ENUM existente, uma simples UPDATE fará isso.Para adicionar um novo valor ENUM:
pg_enum
. Se o novo valor tiver que ser o último, você está pronto.pg_enum
ordem oposta.Ilustração
Você tem o seguinte conjunto de etiquetas:
e você deseja obter:
então:
então:
E assim por diante...
fonte
Não consigo postar um comentário, então vou apenas dizer que a atualização do pg_enum funciona no Postgres 8.4. Para a maneira como nossas enumerações são configuradas, adicionamos novos valores aos tipos de enumerações existentes através de:
É um pouco assustador, mas faz sentido, dada a maneira como o Postgres realmente armazena seus dados.
fonte
A atualização de pg_enum funciona, assim como o truque da coluna intermediária destacado acima. Pode-se também usar USING magic para alterar diretamente o tipo da coluna:
Contanto que você não tenha funções que exijam explicitamente ou retornem essa enumeração, você é bom. (O pgsql reclamará quando você soltar o tipo, se houver.)
Além disso, observe que o PG9.1 está introduzindo uma instrução ALTER TYPE, que funcionará em enumerações:
http://developer.postgresql.org/pgdocs/postgres/release-9-1-alpha.html
fonte
ALTER TABLE foo ALTER COLUMN bar TYPE test USING bar::text::new_type;
Mas em grande parte irrelevante agora ...... USING bar::type
funcionou para mim. Eu nem precisei especificar::text
.Mais simples: livre-se das enumerações. Eles não são facilmente modificáveis e, portanto, devem muito raramente ser usados.
fonte
Não é possível adicionar um comentário ao local apropriado, mas
ALTER TABLE foo ALTER COLUMN bar TYPE new_enum_type USING bar::text::new_enum_type
com um padrão na coluna falhou. Eu precisei:ALTER table ALTER COLUMN bar DROP DEFAULT
;e então funcionou.
fonte
por precaução, se você estiver usando o Rails e tiver várias instruções, precisará executar uma por uma, como:
fonte
Aqui está uma solução mais geral, mas bastante rápida, que além de alterar o tipo atualiza todas as colunas no banco de dados usando-o. O método pode ser aplicado mesmo que uma nova versão do ENUM seja diferente em mais de um rótulo ou perca alguns dos originais. O código abaixo substitui
my_schema.my_type AS ENUM ('a', 'b', 'c')
porENUM ('a', 'b', 'd', 'e')
:Todo o processo será executado rapidamente, porque se a ordem dos rótulos persistir, nenhuma mudança real de dados ocorrerá. Eu apliquei o método em 5 tabelas usando
my_type
e tendo 50.000 a 70.000 linhas em cada uma, e todo o processo levou apenas 10 segundos.Obviamente, a função retornará uma exceção no caso de rótulos ausentes na nova versão do ENUM serem usados em algum lugar nos dados, mas nessa situação algo deve ser feito de qualquer maneira com antecedência.
fonte
Para quem procura uma solução em transação, o seguinte parece funcionar.
Em vez de um
ENUM
, aDOMAIN
deve ser usado no tipoTEXT
com uma restrição, verificando se o valor está dentro da lista especificada de valores permitidos (conforme sugerido por alguns comentários). O único problema é que nenhuma restrição pode ser adicionada (e, portanto, nem modificada) a um domínio se for usada por qualquer tipo composto (os documentos dizem apenas que "isso deve ser melhorado"). Essa restrição pode ser contornada, no entanto, usando uma restrição que chama uma função, da seguinte maneira.Anteriormente, usei uma solução semelhante à resposta aceita, mas está longe de ser boa quando são consideradas visualizações ou funções ou tipos compostos (e principalmente visualizações usando outras visualizações usando os ENUMs modificados ...). A solução proposta nesta resposta parece funcionar sob quaisquer condições.
A única desvantagem é que nenhuma verificação é executada nos dados existentes quando alguns valores permitidos são removidos (o que pode ser aceitável, especialmente para esta pergunta).
ALTER DOMAIN test_domain VALIDATE CONSTRAINT val_check
Infelizmente, uma chamada termina com o mesmo erro que adicionar uma nova restrição ao domínio usado por um tipo composto.Observe que uma leve modificação, como(funciona, na verdade - foi o meu erro)CHECK (value = ANY(get_allowed_values()))
onde aget_allowed_values()
função retornou a lista de valores permitidos, não funcionaria - o que é bastante estranho, então espero que a solução proposta acima funcione de maneira confiável (funciona para mim até agora ...).fonte
Como discutido acima, o
ALTER
comando não pode ser gravado dentro de uma transação. A maneira sugerida é inserir diretamente na tabela pg_enum, porretrieving the typelem from pg_type table
ecalculating the next enumsortorder number
;A seguir está o código que eu uso. (Verifica se existe um valor duplicado antes da inserção (restrição entre o nome da enumtypid e a enumlabel)
Observe que o nome do seu tipo é anexado com um sublinhado na tabela pg_type. Além disso, o nome do tipo deve estar em letras minúsculas na cláusula where.
Agora isso pode ser gravado com segurança no seu script db migrate.
fonte
Não sei se tenho outra opção, mas podemos diminuir o valor usando:
fonte
Ao usar o Navicat, você pode acessar os tipos (em exibição -> outros -> tipos) - obter a visualização do design do tipo - e clicar no botão "adicionar rótulo".
fonte
ERROR: cannot drop type foo because other objects depend on it HINT: Use DROP ... CASCADE to drop the dependent objects too.