当一个表中的两列指向另一个表中的主键时,避免循环引用
Posted
技术标签:
【中文标题】当一个表中的两列指向另一个表中的主键时,避免循环引用【英文标题】:Avoid circular reference when two columns in one table point to primary key in another table 【发布时间】:2020-07-17 11:31:12 【问题描述】:我有两张桌子。第一个是Users
表,第二个是Referrals
表。引荐表如下所示:
| Referrals table columns | Points to
| ----------------------- | ---
| new_customer_id | user table's primary key
| referred_by | user table's primary key
要求是如果 Person B (ID: 2) 由 Person A (ID: 1) 引用,我们应该不能以相反的方式插入。换句话说,表不应该有这样的数据:
| new_customer_id | referred_by |
| --------------- | ----------- |
| 2 | 1 | <-- OK
| 1 | 2 | <-- Both people refering each other should not be allowed
是否可以在数据库级别插入时检查这一点。我正在使用mysql。我读了一些关于 mysql CHECK 约束here 的内容,但不知道如何实现。
我正在使用 django ORM,这是我尝试过但失败的方法。
class Referrals(models.Model):
customer = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, db_index=True)
referred_by = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, db_index=True)
class Meta:
constraints = [
models.CheckConstraint(check=models.Q(customer__gt=models.F('referred_by')),
name='referrer_should_come_before_referee')
]
如果 Django ORM 无法实现,但在数据库级别可以通过某些查询实现,那也没关系。但是,对于 django 解决方案 +1。 :)
谢谢。
【问题讨论】:
【参考方案1】:您不能创建引用其他行的 CHECK 约束。它必须在一行内进行评估。
但您可以创建一个 CHECK 约束,要求较小的 id 值位于第一列。
mysql> create table referrals (
referral1 int,
referral2 int,
check (referral1 < referral2)
);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into referrals values (1,2);
Query OK, 1 row affected (0.01 sec)
mysql> insert into referrals values (2,1);
ERROR 3819 (HY000): Check constraint 'referrals_chk_1' is violated.
然后,您可以通过在这两列上放置 UNQIUE KEY 来防止两个人之间进行多次推荐。
alter table referrals add unique key (referral1, referral2);
如果 CHECK 约束要求第一个数字较小,而 UNIQUE KEY 约束确保相同的两个数字不会出现在另一行,这将防止同一对人再次出现。
您还希望表格中的一列指定两个人中的哪一个是被推荐人,哪个是被推荐人。
请注意,仅 MySQL 8.0.16 及更高版本支持 CHECK 约束。如果您使用的是早期版本的 MySQL,则可以是 simulated with a trigger。
【讨论】:
谢谢。在我升级到 mysql 8.0.19 后它已修复以上是关于当一个表中的两列指向另一个表中的主键时,避免循环引用的主要内容,如果未能解决你的问题,请参考以下文章