Nie widzę tu nic cyklicznego. Pomiędzy tymi podmiotami są ludzie i posty oraz dwa niezależne relacje. Postrzegałbym polubienia jako realizację jednego z tych związków.
- Osoba może napisać wiele postów, post jest napisany przez jedną osobę:
1:n
- Osoba może jak wiele postów, post może być lubiany przez wielu ludzi:
n:m
n: m relacje mogą być realizowane z inną zależnością likes
.
Podstawowe wdrożenie
Podstawowa implementacja może wyglądać tak w 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)
);
W szczególności pamiętaj, że post musi mieć autora ( NOT NULL
), a istnienie polubień jest opcjonalne. Dla istniejących lubi, jednak post
i person
musi być zarówno odniesienia (egzekwowane przez PRIMARY KEY
sprawia, że obie kolumny NOT NULL
automatycznie (można dodać te ograniczenia wyraźnie, nadmiarowo) tak anonimowe sympatie są również niemożliwe.
Szczegóły implementacji n: m:
Zapobiegaj samolubstwu
Napisałeś także:
(utworzona osoba nie może polubić własnego posta).
Nie jest to jeszcze wymuszone w powyższej implementacji. Możesz użyć wyzwalacza .
Lub jedno z tych szybszych / bardziej niezawodnych rozwiązań:
Solidny za cenę
Jeśli musi być solidne , można przedłużyć z FK likes
do post
celu obejmują author_id
nadmiarowo. Następnie możesz wykluczyć kazirodztwo za pomocą prostego CHECK
ograniczenia.
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)
);
To wymaga się inaczej także zbędne UNIQUE
ograniczenia w post
:
ALTER TABLE post ADD CONSTRAINT post_for_fk_uni UNIQUE (author_id, post_id);
Stawiam na author_id
pierwszym miejscu, aby podać użyteczny indeks , będąc przy nim.
Powiązana odpowiedź z więcej:
Tańsze z CHECK
ograniczeniem
Opierając się na „Podstawowej implementacji” powyżej.
CHECK
ograniczenia mają być niezmienne. Odwoływanie się do innych tabel w celu sprawdzenia nigdy nie jest niezmienne, tutaj trochę nadużywamy tej koncepcji. Proponuję zadeklarować ograniczenie, NOT VALID
aby właściwie to odzwierciedlić. Detale:
W CHECK
tym konkretnym przypadku ograniczenie wydaje się rozsądne, ponieważ autor postu wydaje się atrybutem, który nigdy się nie zmienia. Aby mieć pewność, nie zezwalaj na aktualizacje tego pola.
Mamy fałszyweIMMUTABLE
funkcja:
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;
Zamień „public” na rzeczywisty schemat swoich tabel.
Użyj tej funkcji jako CHECK
ograniczenia:
ALTER TABLE likes ADD CONSTRAINT no_self_like_chk
CHECK (f_author_id_of_post(post_id) <> person_id) NOT VALID;