Избегайте циклических ссылок, когда два столбца в одной таблице указывают на первичный ключ в другой таблице - PullRequest
1 голос
/ 05 апреля 2020

У меня есть две таблицы. Первый - Users таблица, а второй - Referrals таблица. Таблица рефералов выглядит следующим образом:

| 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), мы не сможем вставлять наоборот. Другими словами, в таблице не должно быть таких данных:

| new_customer_id | referred_by |
| --------------- | ----------- |
|       2         |      1      | <-- OK
|       1         |      2      | <-- Both people refering each other should not be allowed

Можно ли это проверить во время вставки на уровне базы данных . Я использую mysql. Я прочитал немного о mysql CHECK ограничение здесь , но не могу понять, как это реализовать.

Я использую 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 решения. :)

Спасибо.

1 Ответ

1 голос
/ 05 апреля 2020

Нельзя создать ограничение CHECK, которое ссылается на другие строки. Он должен оцениваться в одной строке.

Но вы можете сделать ограничение CHECK, которое требует, чтобы меньшее значение идентификатора было в первом столбце.

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 в эти два столбца.

alter table referrals add unique key (referral1, referral2);

Если ограничение CHECK требует, чтобы первое число было меньшим, а ограничение UNIQUE KEY гарантирует, что те же самые два числа не он может появиться уже в другой строке, что предотвратит повторное появление одной и той же пары людей.

Вы также хотели бы, чтобы столбец в таблице указывал, какой из двух людей ссылается, а какой - упомянутый.


Обратите внимание, что ограничения CHECK поддерживаются только в MySQL 8.0.16 и более поздних версиях. Если вы используете более раннюю версию MySQL, их можно смоделировать с помощью триггера .

...