Ich sehe hier nichts Zyklisches. Es gibt Personen und Stellen und zwei unabhängige Beziehungen zwischen diesen Entitäten. Ich würde Likes als die Implementierung einer dieser Beziehungen sehen.
- Eine Person kann viele Beiträge schreiben, ein Beitrag wird von einer Person geschrieben:
1:n
- Eine Person kann viele Beiträge mögen, ein Beitrag kann vielen Menschen gefallen:
n:m
Die n: m-Beziehung kann mit einer anderen Beziehung implementiert werden : likes
.
Grundlegende Implementierung
Die grundlegende Implementierung könnte in PostgreSQL folgendermaßen aussehen :
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)
);
Insbesondere ist zu beachten , dass ein Beitrag muss einen Autor hat ( NOT NULL
), während die Existenz von Gleichen sind optional. Für bestehende mag jedoch post
und person
muss sowohl durch die referenzierte (erzwungen werden , PRIMARY KEY
die beide Spalten macht NOT NULL
automatisch (Sie könnten diese Einschränkungen ausdrücklich hinzufügen, redundant) so anonym Gleichen sind auch unmöglich.
Details zur n: m-Implementierung:
Verhindern Sie selbstähnlich
Sie haben auch geschrieben:
(Erstellte Person kann ihren eigenen Beitrag nicht mögen).
Dies ist in der obigen Implementierung noch nicht erzwungen. Sie könnten einen Auslöser verwenden .
Oder eine dieser schnelleren / zuverlässigeren Lösungen:
Für einen Preis absolut solide
Wenn es sein muss rock-solid , könnten Sie den FK erstrecken sich von likes
bis post
zu den sind author_id
redundant. Dann können Sie Inzest mit einer einfachen CHECK
Einschränkung ausschließen.
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)
);
Dies erfordert eine ansonsten auch redundante UNIQUE
Einschränkung in post
:
ALTER TABLE post ADD CONSTRAINT post_for_fk_uni UNIQUE (author_id, post_id);
Ich habe author_id
zuerst einen nützlichen Index geliefert, während ich dabei bin.
Verwandte Antwort mit mehr:
Billiger mit einer CHECK
Einschränkung
Aufbauend auf der obigen "Basisimplementierung".
CHECK
Einschränkungen sollen unveränderlich sein. Das Verweisen auf andere Tabellen zur Überprüfung ist niemals unveränderlich. Wir missbrauchen das Konzept hier ein wenig. Ich schlage vor, die Einschränkung zu deklarieren, NOT VALID
um dies angemessen widerzuspiegeln. Einzelheiten:
Eine CHECK
Einschränkung erscheint in diesem speziellen Fall vernünftig, da der Autor eines Beitrags wie ein Attribut erscheint, das sich nie ändert. Aktualisierungen für dieses Feld sind nicht zulässig, um sicherzugehen.
Wir fälschen eine IMMUTABLE
Funktion:
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;
Ersetzen Sie 'public' durch das tatsächliche Schema Ihrer Tabellen.
Verwenden Sie diese Funktion in einer CHECK
Einschränkung:
ALTER TABLE likes ADD CONSTRAINT no_self_like_chk
CHECK (f_author_id_of_post(post_id) <> person_id) NOT VALID;