如何在 MySQL 中有一个涉及 ForeignKey 字段的 unique_together 约束?

Posted

技术标签:

【中文标题】如何在 MySQL 中有一个涉及 ForeignKey 字段的 unique_together 约束?【英文标题】:How can I have a unique_together constraint involving a ForeignKey field in MySQL? 【发布时间】:2011-10-31 04:36:07 【问题描述】:

mysql 在具有外键的多列唯一约束方面似乎有点坏了。这是我能想出的最小示例来展示这一点(使用 MySQL/InnoDB):

models.py

from django.db import models

class Team(models.Model):
    pass

class Player(models.Model):
    team = models.ForeignKey(Team)
    number = models.PositiveIntegerField()

    class Meta:
        unique_together = ("team", "number")

运行schemamigration --initial,南吐出以下迁移(仅重要位):

class Migration(SchemaMigration):                                                                                                                                                
    def forwards(self, orm):
        # Adding model 'Team'
        db.create_table('fkuniq_team', (
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
        ))
        db.send_create_signal('fkuniq', ['Team'])

        # Adding model 'Player'
        db.create_table('fkuniq_player', (
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
            ('team', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['fkuniq.Team'])),
            ('number', self.gf('django.db.models.fields.PositiveIntegerField')()),
        ))
        db.send_create_signal('fkuniq', ['Player'])

        # Adding unique constraint on 'Player', fields ['team', 'number']
        db.create_unique('fkuniq_player', ['team_id', 'number'])

在 MySQL 中:

mysql> SHOW COLUMNS FROM fkuniq_player;
+---------+------------------+------+-----+---------+----------------+
| Field   | Type             | Null | Key | Default | Extra          |
+---------+------------------+------+-----+---------+----------------+
| id      | int(11)          | NO   | PRI | NULL    | auto_increment |
| team_id | int(11)          | NO   | MUL | NULL    |                |
| number  | int(10) unsigned | NO   |     | NULL    |                |
+---------+------------------+------+-----+---------+----------------+

我认为 south 默默地未能创建我想要的唯一约束。在Key 列中,我看到id 上的主键索引和team_id 上的外键索引,但number 行中也应该有一个MUL,因为应该有一个UNIQUE 索引它与team_id。此外,从模型中删除 unique_together 约束会导致下一次迁移失败并出现错误:

Traceback (most recent call last):
  ...
  File "/home/aogier/uniques/../uniques/fkuniq/migrations/0002_auto__del_unique_player_number_team.py", line 12, in forwards
    db.delete_unique('fkuniq_player', ['number', 'team_id'])
  File "/home/aogier/.virtualenvs/uniques/lib/python2.7/site-packages/south/db/generic.py", line 479, in delete_unique
    raise ValueError("Cannot find a UNIQUE constraint on table %s, columns %r" % (table_name, columns))
ValueError: Cannot find a UNIQUE constraint on table fkuniq_player, columns ['number', 'team_id']

我认为它丢失了,因为当外键约束和多列UNIQUE 约束重合时,MySQL 不能很好地发挥作用。在ALTER TABLE 的 MySQL 文档中有一个关于这种效果的评论:http://dev.mysql.com/doc/refman/5.1/en/alter-table.html(见大约一半,Hadi Rastgou 的评论)。

无论如何,很抱歉这个问题很长:有没有人有办法让这个工作?即使我必须在原始 SQL 中编写特定于 MySQL 的查询,我也希望在迁移中采用一种干净的方式来执行此操作。或者,这在 MySQL 中是完全不可能做到的,在我花更多时间做这件事之前,最好知道这一点。

【问题讨论】:

【参考方案1】:

啊,我自己解决了这个问题。这是南方的一个已知错误,已在他们的开发分支中修复。 http://south.aeracode.org/ticket/747

【讨论】:

以上是关于如何在 MySQL 中有一个涉及 ForeignKey 字段的 unique_together 约束?的主要内容,如果未能解决你的问题,请参考以下文章

假设一个表中有多个列有 1000 条记录,如何在整个表中查找重复记录? [复制]

是php-mysql:根据涉及PHP变量的条件更新具有不同值的列

MySQL 中的外键添加失败,错误代码为 1005,编号为 150

三战MySQL数据库终极篇

三战MySQL数据库终极篇

三战MySQL数据库终极篇