Я не вижу здесь ничего цикличного. Есть люди и должности и два независимых отношения между этими объектами. Я бы увидел лайков как реализацию одного из этих отношений.
- Человек может написать много постов, пост написан одним человеком:
1:n
- Человек может любить много постов, пост может быть любимым многими людьми:
n:m
п: отношения м могут быть реализованы с другим соотношением: likes
.
Основная реализация
Базовая реализация может выглядеть так в PostgreSQL :
CREATE TABLE person (
person_id serial PRIMARY KEY
, person text NOT NULL
);
CREATE TABLE post (
post_id serial PRIMARY KEY
, author_id int NOT NULL -- cannot be anonymous
REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE -- 1:n relationship
, post text NOT NULL
);
CREATE TABLE likes ( -- n:m relationship
person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE
, post_id int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE
, PRIMARY KEY (post_id, person_id)
);
Обратите внимание, в частности, что пост должен иметь author ( NOT NULL
), в то время как наличие лайков необязательно. Однако для существующих лайков, post
и на них person
должны ссылаться оба (принудительно, PRIMARY KEY
что делает оба столбца NOT NULL
автоматически (вы можете добавить эти ограничения явно, избыточно), поэтому анонимные лайки также невозможны.
Детали для реализации n: m:
Предотвратить самоподобный
Вы также написали:
(созданному человеку не может понравиться его собственный пост).
Это не применяется в приведенной выше реализации, пока. Вы могли бы использовать триггер .
Или одно из этих более быстрых / более надежных решений:
Отличная цена
Если он должен быть незыблемыми , вы можете расширить FK от likes
до , post
чтобы включать в себя author_id
избыточно. Тогда вы можете исключить инцест с помощью простого CHECK
ограничения.
CREATE TABLE likes (
person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE
, post_id int
, author_id int NOT NULL
, CONSTRAINT likes_pkey PRIMARY KEY (post_id, person_id)
, CONSTRAINT likes_post_fkey FOREIGN KEY (author_id, post_id)
REFERENCES post(author_id, post_id) ON UPDATE CASCADE ON DELETE CASCADE
, CONSTRAINT no_self_like CHECK (person_id <> author_id)
);
Это требует иного также избыточного UNIQUE
ограничения в post
:
ALTER TABLE post ADD CONSTRAINT post_for_fk_uni UNIQUE (author_id, post_id);
author_id
Сначала я поставил полезный индекс , находясь при этом.
Связанный ответ с более:
Дешевле с CHECK
ограничением
Опираясь на «Базовую реализацию» выше.
CHECK
ограничения должны быть неизменными. Ссылка на другие таблицы для проверки никогда не бывает неизменной, здесь мы немного злоупотребляем этой концепцией. Я предлагаю объявить ограничение, NOT VALID
чтобы должным образом отразить это. Подробности:
CHECK
Ограничение представляется разумным в данном конкретном случае, так как автор поста , кажется , как атрибут , который никогда не меняется. Запретить обновления в этом поле, чтобы быть уверенным.
Мы поддельнаяIMMUTABLE
функция:
CREATE OR REPLACE FUNCTION f_author_id_of_post(_post_id int)
RETURNS int AS
'SELECT p.author_id FROM public.post p WHERE p.post_id = $1'
LANGUAGE sql IMMUTABLE;
Замените «public» фактической схемой ваших таблиц.
Используйте эту функцию в CHECK
ограничении:
ALTER TABLE likes ADD CONSTRAINT no_self_like_chk
CHECK (f_author_id_of_post(post_id) <> person_id) NOT VALID;