Я не вижу здесь ничего цикличного. Есть люди и должности и два независимых отношения между этими объектами. Я бы увидел лайков как реализацию одного из этих отношений.
- Человек может написать много постов, пост написан одним человеком:
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;