347 votes

Ajout d'une nouvelle valeur à un type ENUM existant

J'ai une colonne de table qui utilise un enum type. Je souhaite mettre à jour ce enum pour avoir une valeur supplémentaire possible. Je ne veux pas supprimer les valeurs existantes, mais simplement ajouter la nouvelle valeur. Quelle est la façon la plus simple de procéder ?

659voto

Dariusz Points 2845

PostgreSQL 9.1 introduit la capacité de ALTER Types d'énumération :

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';

3 votes

Qu'est-ce que le "enum_type" ? nom du champ, nom du champ de la table ? ou quelque chose d'autre ? comment dois-je le saisir ? J'ai une table "grades" et une colonne "type" et dans le vidage de la base de données j'obtiens ceci : CONSTRAINT grades_type_check CHECK (((type)::text = ANY ((ARRAY['exam'::character varying, 'test'::character varying, 'extra'::character varying, 'midterm'::character varying, 'final'::character varying])::text[])))))

2 votes

Enum_type est juste le nom de votre propre type d'enum @mariotanenbaum. Si votre enum est un "type", c'est ce que vous devez utiliser.

0 votes

Hm, je ne comprends pas. Je pense avoir été assez clair. J'ai une colonne dans une table appelée "type", en fait elle est enregistrée comme un varchar. Et pour cette même colonne, j'ai une contrainte qui la définit comme étant l'une des valeurs d'un tableau. C'est donc un enum. J'ai essayé toutes les variantes qui me sont venues à l'esprit mais rien n'a fonctionné. Je ne sais pas quoi faire maintenant...

215voto

taksofan Points 502

NOTA si vous utilisez PostgreSQL 9.1 ou une version ultérieure, et si vous êtes d'accord pour effectuer des modifications en dehors d'une transaction, consultez le site suivant cette réponse pour une approche plus simple.


J'ai eu le même problème il y a quelques jours et j'ai trouvé ce post. Ma réponse peut donc être utile à quelqu'un qui cherche une solution :)

Si vous n'avez qu'une ou deux colonnes qui utilisent le type d'énumération que vous voulez modifier, vous pouvez essayer ceci. Vous pouvez également modifier l'ordre des valeurs dans le nouveau type.

-- 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;

Les étapes 3 à 6 doivent être répétées s'il y a plus d'une colonne.

13 votes

Il convient de mentionner que tout cela peut être effectué en une seule transaction, ce qui permet de le faire en toute sécurité dans une base de données de production.

72 votes

Cela n'a jamais été une bonne idée. Depuis 9.1, vous pouvez tout faire avec ALTER TYPE . Mais même avant ça, ALTER TABLE foo ALTER COLUMN bar TYPE new_type USING bar::text::new_type; était de loin supérieure.

1 votes

Sachez que les anciennes versions de Postgres ne prennent pas en charge le renommage des types. En particulier, la version de Postgres sur Heroku (shared db, je crois qu'ils utilisent PG 8.3) ne le supporte pas.

75voto

Steffen Points 101

Une solution possible est la suivante ; la condition préalable est qu'il n'y ait pas de conflits dans les valeurs d'énumération utilisées. (par exemple, lorsque vous supprimez une valeur d'enum, assurez-vous que cette valeur n'est plus utilisée).

-- 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__;

De cette manière, l'ordre des colonnes ne sera pas modifié.

2 votes

+1 c'est la façon de faire avant 9.1 et c'est toujours la façon de faire pour supprimer ou modifier des éléments.

0 votes

C'est de loin la meilleure réponse pour ma solution, qui ajoute de nouveaux enums à un type d'enum existant, où nous gardons tous les anciens enums et en ajoutons de nouveaux. De plus, notre mise à jour script est transactionnelle. Excellent article !

1 votes

Une réponse brillante ! Évite les hacks autour pg_enum qui peut réellement casser des choses et qui est transactionnel, contrairement à ALTER TYPE ... ADD .

44voto

Lev Denisov Points 397

Si vous utilisez Postgres 12 (ou une version ultérieure), vous pouvez simplement exécuter ALTER TYPE ... ADD VALUE à l'intérieur d'une transaction ( documentation ).

Si ALTER TYPE ... ADD VALUE (le formulaire qui ajoute une nouvelle valeur à un type d'enum type) est exécuté à l'intérieur d'un bloc de transaction, la nouvelle valeur ne peut être nouvelle valeur ne peut être utilisée qu'après la validation de la transaction.

Il n'est donc pas nécessaire d'intervenir dans les migrations.

UPD : voici un exemple (merci à Nick pour cela)

ALTER TYPE enum_type ADD VALUE 'new_value';

1 votes

Ouaip, exemple : ALTER TYPE enum_type ADD VALUE 'new_value'; Merci !

25voto

Kiko Castro Points 175

Complétant @Dariusz 1

Pour Rails 4.2.1, il y a cette section de la doc :

\== Migrations transactionnelles

Si l'adaptateur de base de données prend en charge les transactions DDL, toutes les migrations vont automatiquement enveloppées dans une transaction. Il y a des requêtes que vous que vous ne pouvez pas exécuter à l'intérieur d'une transaction. vous pouvez désactiver les transactions automatiques.

class ChangeEnum < ActiveRecord::Migration
  disable_ddl_transaction!

  def up
    execute "ALTER TYPE model_size ADD VALUE 'new_value'"
  end
end

3 votes

Si vous jouez avec les enums dans les rails modernes, c'est exactement ce que vous recherchez.

1 votes

Super, ça m'a beaucoup aidé !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X