I am trying to alter a column’s type from ENUM to INTEGER (which is also a foreign key) in PostgreSQL using Alembic. However, when I attempt to upgrade the migration, I encounter the following error:
sqlalchemy.exc.ProgrammingError: (psycopg2.errors.CannotCoerce) cannot cast type serie_enum to integer
LINE 1: …R COLUMN serie_aluno TYPE INTEGER USING serie_aluno::integer
[SQL: ALTER TABLE aluno ALTER COLUMN serie_aluno TYPE INTEGER USING serie_aluno::integer]
Here is the migration file generated by Alembic:
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('aluno', 'serie_aluno',
existing_type=postgresql.ENUM('6', '7', '8', '9', name='serie_enum'),
type_=sa.Integer(),
existing_nullable=False,
postgresql_using="NULL")
op.create_foreign_key(None, 'aluno', 'serie', ['serie_aluno'], ['id_serie'])
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'aluno', type_='foreignkey')
op.alter_column('aluno', 'serie_aluno',
existing_type=sa.Integer(),
type_=postgresql.ENUM('6', '7', '8', '9', name='serie_enum'),
existing_nullable=False)
# ### end Alembic commands ###
How can I successfully convert a column from ENUM to INTEGER while ensuring the foreign key constraint is created correctly?
2
Answers
There is no cast defined from your custom enum type
serie_aluno
tointeger
. (Unless you create such a cast explicitly.)But everything can be cast to
text
. If all enum values are represented by valid integer literals, you can usetext
as stepping stone:To then add a
FOREIGN KEY
constraint pointing to aninteger
column:Or do it in a single ALTER TABLE command:
fiddle
This is kind of messy but I had to make the column nullable with one alter before I could make the subsequent alter to change the type and set all the values to
NULL
. You can actually migrate the enum to hardcoded ints if you know the mapping and use aCASE
statement which you said you didn’t need but I thought was pretty cool.