当一个 table 中的两列指向另一个 table 中的主键时避免循环引用
Avoid circular reference when two columns in one table point to primary key in another table
我有两个 table。第一个是 Users
table,第二个是 Referrals
table。推荐 table 看起来像这样:
| Referrals table columns | Points to
| ----------------------- | ---
| new_customer_id | user table's primary key
| referred_by | user table's primary key
要求是如果B (ID: 2) 被A (ID: 1) 推荐,我们不应该能够反过来插入。换句话说,table 不应该有这样的数据:
| 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 无法实现,但可以通过某些查询在数据库级别实现,那也没关系。但是,+1 用于 django 解决方案。 :)
谢谢。
您不能创建引用其他行的 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 约束确保相同的两个数字不会出现在另一行中,这将防止同一对人出现第二个时间.
您还需要 table 中的一列来指定两个人中的哪一个是推荐人,哪个是推荐人。
请注意,CHECK 约束仅在 MySQL 8.0.16 及更高版本中受支持。如果您使用 MySQL 的早期版本,它们可以是 simulated with a trigger.
我有两个 table。第一个是 Users
table,第二个是 Referrals
table。推荐 table 看起来像这样:
| Referrals table columns | Points to
| ----------------------- | ---
| new_customer_id | user table's primary key
| referred_by | user table's primary key
要求是如果B (ID: 2) 被A (ID: 1) 推荐,我们不应该能够反过来插入。换句话说,table 不应该有这样的数据:
| 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 无法实现,但可以通过某些查询在数据库级别实现,那也没关系。但是,+1 用于 django 解决方案。 :)
谢谢。
您不能创建引用其他行的 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 约束确保相同的两个数字不会出现在另一行中,这将防止同一对人出现第二个时间.
您还需要 table 中的一列来指定两个人中的哪一个是推荐人,哪个是推荐人。
请注意,CHECK 约束仅在 MySQL 8.0.16 及更高版本中受支持。如果您使用 MySQL 的早期版本,它们可以是 simulated with a trigger.