Je ne vois rien de cyclique ici. Il existe des personnes et des postes et deux relations indépendantes entre ces entités. Je verrais les goûts comme la mise en œuvre de l'une de ces relations.
- Une personne peut écrire plusieurs articles, un article est écrit par une seule personne:
1:n
- Une personne peut comme de nombreux postes, un poste peut être aimé par de nombreuses personnes:
n:m
Le n: relation m peut être mis en œuvre avec une autre relation: likes
.
Implémentation de base
L'implémentation de base pourrait ressembler à ceci dans 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)
);
Notez en particulier qu'un article doit avoir un auteur ( NOT NULL
), alors que l'existence de likes est facultative. Pour les likes existants, cependant, post
et person
doivent tous deux être référencés (imposé par le PRIMARY KEY
qui rend les deux colonnes NOT NULL
automatiquement (vous pouvez ajouter ces contraintes de manière explicite, redondante), donc les likes anonymes sont également impossibles.
Détails pour l'implémentation n: m:
Empêcher le self-like
Vous avez également écrit:
(la personne créée ne peut pas aimer son propre message).
Cela n'est pas encore appliqué dans la mise en œuvre ci-dessus. Vous pouvez utiliser un déclencheur .
Ou l'une de ces solutions plus rapides / plus fiables:
Solide comme un roc pour un coût
S'il doit être solide comme le roc , vous pouvez étendre le FK de likes
à post
pour l'inclure de manière author_id
redondante. Ensuite, vous pouvez exclure l'inceste avec une simple CHECK
contrainte.
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)
);
Cela nécessite une UNIQUE
contrainte sinon également redondante dans post
:
ALTER TABLE post ADD CONSTRAINT post_for_fk_uni UNIQUE (author_id, post_id);
Je mets d' author_id
abord à fournir un indice utile tout en y étant.
Réponse connexe avec plus:
Moins cher avec une CHECK
contrainte
S'appuyant sur la «mise en œuvre de base» ci-dessus.
CHECK
les contraintes sont censées être immuables. Référencer d'autres tables pour une vérification n'est jamais immuable, nous abusons un peu du concept ici. Je suggère de déclarer la contrainte NOT VALID
pour bien refléter cela. Détails:
Une CHECK
contrainte semble raisonnable dans ce cas particulier, car l'auteur d'un article semble être un attribut qui ne change jamais. Interdisez les mises à jour de ce champ pour être sûr.
On simule une IMMUTABLE
fonction:
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;
Remplacez «public» par le schéma réel de vos tables.
Utilisez cette fonction dans une CHECK
contrainte:
ALTER TABLE likes ADD CONSTRAINT no_self_like_chk
CHECK (f_author_id_of_post(post_id) <> person_id) NOT VALID;