Adding a new value to an existing ENUM Type

前端 未结 18 1297
春和景丽
春和景丽 2020-12-04 04:52

I have a table column that uses an enum type. I wish to update that enum type to have an additional possible value. I don\'t want to delete any exi

相关标签:
18条回答
  • 2020-12-04 05:23

    NOTE if you're using PostgreSQL 9.1 or later, and you are ok with making changes outside of a transaction, see this answer for a simpler approach.


    I had the same problem few days ago and found this post. So my answer can be helpful for someone who is looking for solution :)

    If you have only one or two columns which use the enum type you want to change, you can try this. Also you can change the order of values in the new 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;
    

    3-6 should be repeated if there is more than 1 column.

    0 讨论(0)
  • 2020-12-04 05:23

    A possible solution is the following; precondition is, that there are not conflicts in the used enum values. (e.g. when removing an enum value, be sure that this value is not used anymore.)

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

    Also in this way the column order will not be changed.

    0 讨论(0)
  • 2020-12-04 05:24

    I can't seem to post a comment, so I'll just say that updating pg_enum works in Postgres 8.4 . For the way our enums are set up, I've added new values to existing enum types via:

    INSERT INTO pg_enum (enumtypid, enumlabel)
      SELECT typelem, 'NEWENUM' FROM pg_type WHERE
        typname = '_ENUMNAME_WITH_LEADING_UNDERSCORE';
    

    It's a little scary, but it makes sense given the way Postgres actually stores its data.

    0 讨论(0)
  • 2020-12-04 05:24

    Simplest: get rid of enums. They are not easily modifiable, and thus should very rarely be used.

    0 讨论(0)
  • 2020-12-04 05:27

    From Postgres 9.1 Documentation:

    ALTER TYPE name ADD VALUE new_enum_value [ { BEFORE | AFTER } existing_enum_value ]
    

    Example:

    ALTER TYPE user_status ADD VALUE 'PROVISIONAL' AFTER 'NORMAL'
    
    0 讨论(0)
  • 2020-12-04 05:31

    As discussed above, ALTER command cannot be written inside a transaction. The suggested way is to insert into the pg_enum table directly, by retrieving the typelem from pg_type table and calculating the next enumsortorder number;

    Following is the code that I use. (Checks if duplicate value exists before inserting (constraint between enumtypid and enumlabel name)

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

    Note that your type name is prepended with an underscore in the pg_type table. Also, the typname needs to be all lowercase in the where clause.

    Now this can be written safely into your db migrate script.

    0 讨论(0)
提交回复
热议问题