Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
242 views
in Technique[技术] by (71.8m points)

sql server - Alembic MSSQL Unique Constraint Allow Nulls

Problem to Solve

Using MSSQL I'd like to have a column that is unique and accepts nulls.

Issues

  1. Add two rows of data into a column that allows nulls with the unique constraint like in the implementation below gives the following error:

    Violation of UNIQUE KEY constraint 'UQ_...'. Cannot insert duplicate key in 
    object 'TABLE'. The duplicate key value is (<NULL>). (2627) (SQLExecDirectW)"
    
  2. Downgrading the column causes constraint issues tied to the reference column. The constraint is automatically uniquely named so its a pain to programmatically remove.

Current Implementation

The alembic operation is:

from alembic import op
import sqlalchemy as sa

#...

def upgrade():
    op.add_column(
        'TABLE', sa.Column('reference', sa.Integer(), nullable=True, unique=True),
    )


def downgrade():
    op.drop_column('TABLE', 'reference')

question from:https://stackoverflow.com/questions/66051383/alembic-mssql-unique-constraint-allow-nulls

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The solution to allowing nulls in a unique field is:

  1. Don't create the unique constraint when defining the column
op.add_column(
        'TABLE', sa.Column('reference', sa.Integer(), nullable=True), # No unique=True
    )
  1. Create a unique index manually
op.create_index(
    'uq_reference_allow_nulls', table_name='TABLE', columns=['reference'],
    mssql_where=sa.text('reference IS NOT NULL'), unique=True,
)
  1. Remove the index when downgrading.
op.drop_index('uq_reference_allow_nulls', table_name='TABLE')

This also solves the problem of having a randomized unique constraint on the table because the unique parameter is removed. All together the alembic revision looks like this:

from alembic import op
import sqlalchemy as sa

#...

def upgrade():
    op.add_column(
        'TABLE', sa.Column('reference', sa.Integer(), nullable=True),  # Do not include unique here
    )
    op.create_index(
        'uq_reference_allow_nulls', table_name='TABLE', columns=['reference'],
        mssql_where=sa.text('reference IS NOT NULL'), unique=True,
    )


def downgrade():
    op.drop_index('uq_reference_allow_nulls', table_name='TABLE')
    op.drop_column('TABLE', 'reference')


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...