Я не бачу, щоб щось тут було циклічним. Між цими сутностями існують люди та посади та два незалежні стосунки. Я б бачив лайки як реалізацію одного з цих відносин.
- Людина може написати багато дописів, допис пише одна людина:
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)
);
Зокрема, зауважте, що у публікації має бути автор ( 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;