Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alembic: IntegrityError: "column contains null values" when adding non-nullable column

I'm adding a column to an existing table. This new column is nullable=False.

op.add_column('mytable', sa.Column('mycolumn', sa.String(), nullable=False))

When I run the migration, it complains:

sqlalchemy.exc.IntegrityError: column "mycolumn" contains null values
like image 981
Ron Avatar asked Nov 14 '15 06:11

Ron


People also ask

Can a nullable column have a default value?

If the column is nullable then it will create the column with a NULL value instead of the default value, however, if column is not nullable and there is a default value, SQL Server has to apply that value to column to avoid violating not null constraint.

What is the difference between a column being nullable and non nullable?

Nullable variables may either contain a valid value or they may not — in the latter case they are considered to be nil . Non-nullable variables must always contain a value and cannot be nil . In Oxygene (as in C# and Java), the default nullability of a variable is determined by its type.

What does it mean for a column to be nullable?

Nullable means it can have a null value, thus not required.


2 Answers

It is because your existing data have no value on that new column, i.e. null. Thus causing said error. When adding a non-nullable column, you must decide what value to give to already-existing data


Alright, existing data should just have "lorem ipsum" for this new column then. But how do I do it? I can't UPDATE because the column is not there yet.

Use the server_default arg:

op.add_column('mytable', sa.Column(     'mycolumn',      sa.String(),      nullable=False,      server_default='lorem ipsum', #  <---  add this )) 

But, but, I don't want it to have default value

Drop it afterwards using op.alter_column('mytable', 'mycolumn', server_default=None)

E.g. your upgrade() function would be:

def upgrade():     op.add_column('mytable', sa.Column('mycolumn', sa.String(), nullable=False, server_default='lorem ipsum'))     op.alter_column('mytable', 'mycolumn', server_default=None) 
like image 129
Ron Avatar answered Sep 19 '22 17:09

Ron


An alternative to @Ron's answer is to do the contrary, and modify the data before adding the constraint:

def upgrade():
    op.add_column('my_table', sa.Column('my_column', sa.String()))
    op.execute('UPDATE my_table SET my_column=my_other_column')
    op.alter_column('my_table', 'my_column', nullable=False)

Seems cleaner and more powerful to me, but you're writing SQL :-).

like image 45
Antoine Lizée Avatar answered Sep 18 '22 17:09

Antoine Lizée