0

I'm not sure if it's actually called "length constraint", but I have a SQL statement that works when testing in a local docker container with mysql:

create unique index _uq_data on data(question_id, reply_id, text(50));

The constraint/length notation (50) is required since the TEXT field is variable length and may make the key too long. When creating a Flask migration for this I tried:

op.create_unique_constraint('_data_uc', 'data', ['question_id', 'reply_id', 'text(50)'])

But the SQL that Alembic generates for this quotes the whole last field:

ALTER TABLE data ADD CONSTRAINT _data_uc UNIQUE (question_id, reply_id, `text(50)`);

which gives the error

ERROR 1072 (42000): Key column 'text(50)' doesn't exist in table

How do I get this emitted as 'text'(50) rather than 'text(50)'?

Per Fagrell
  • 835
  • 7
  • 15

1 Answers1

1

I recently faced the same issue, I considered 2 solutions/workarounds.

First solution

Alter your columns to specify a length to them. In your case, the columns seem to be IDs (as text), will they ever by longer than X characters ?

Second solution

The create_index function allows various things in the columns list, including TextClause. So you can create a non unique index with only a portion of the IDs, such as :

from sqlalchemy.sql.expression import text
from alembic import op

def upgrade():
    op.create_index(
        "_uq_data",
        "data",
        # 100 is arbitrary, but there is a limit to index key length
        # depending on your mysql version and database configuration
        [text("question_id(100)"), text("reply_id(100)")],
        unique=False
    )

Resulting in the following SQL statement :

CREATE INDEX _uq_data ON data (question_id(100), reply_id(100))

Alternative second solution

Still creating a "partial value index", but via sqlalchemy using mysql dialect param mysql_length :

Index(
    "_uq_data",
    "question_id",
    "reply_id",
    unique=False,
    mysql_length={"question_id": 100, "reply_id": 100},
    ),
edg
  • 930
  • 6
  • 17