简体   繁体   中英

Postgres/SQLAlchemy/Alembic change datatype from enum to int and map value with using

I've been using a setup using SQLAlchemy and Alembic migrations together with a Postgres DB in the backend. I've been using enums in some of the DB-Models as datatypes and I've been using the Enum-Type in SQLAlchemy and (because of this) also inside Postgres. Throughout the continuing development I decided to replace those enums with integers, for some smaller reasons (including higher flexibility when adding new values, which would require an DB-migration right now that alters the data-type and altering those in alembic is rather complicated and enums seem to be less portable to other db systems than ints anyways). I have to create a migration because of this that alters the datatype of the enum columns to int using alembic migrations.

Sadly I did not find any conversion method yet, that would allow me to keep the old values throughout the migration. I've been using IntEnums, that map the enum value to integers in python, but Postgres does not use this mapping internally, so it has no information about the supposed value of the enum when converting it to an integer. From my perspective, I have to somehow provide an explicit mapping of enum-name to integer when applying the alter table query. Postgres provides the using statement, but I have been unable to find out how to use this to map the value from my enum-values to the new/old integer values that python has been using anyways.

So how would such using statement have to look like if it should map the old (enum-based) value to a new (int based) value if I had to manually provide a mapping for that?

An example of such an enum:

class SexEnum(enum.IntEnum):
    male = 0
    female = 1

Column (old in the DB):

sex = db.Column(db.Enum(SexEnum))

Column (new):

sex = db.Column(db.Integer)

Migration command right now:

op.alter_column('users', 'sex',
           type_=sa.Integer, postgresql_using='null')

Null probably has to be replaced with something else.

Also, it should be noted that it would be great if the migration would be as compatible to other DB systems as possible, which would force me to use another system than the using statement anyways, wouldn't it?

Okay found it. Thanks to Ilja for the tip with the CASE.

Basically replaced 'null' with

'(CASE sex WHEN \'male\'... END)'

Which brought the migration live without having to set all those values in another way. I dont think this fully fulfills the portability requirement I had, simply because I'm still using the using clause of postgres. Apart from that, the simple case statement works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM