Non vedo nulla di ciclico qui. Ci sono persone e posti e due relazioni indipendenti tra queste entità. Vorrei che i Mi piace fossero l'implementazione di una di queste relazioni.
- Una persona può scrivere molti post, un post è scritto da una persona:
1:n
- Una persona può avere molti post, un post può essere utile a molte persone:
n:m
il n: rapporto m può essere implementato con un altro rapporto: likes
.
Implementazione di base
L'implementazione di base potrebbe apparire così in 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)
);
Nota in particolare che un post deve avere un autore ( NOT NULL
), mentre l'esistenza di mi piace è facoltativa. Per calibro esistenti, tuttavia, post
e person
devono entrambi essere referenziato (recepita con il PRIMARY KEY
che fa entrambe le colonne NOT NULL
automaticamente (è possibile aggiungere questi vincoli in modo esplicito, in modo ridondante) in modo calibro anonimi sono anche impossibile.
Dettagli per l'implementazione n: m:
Prevenire il self-like
Hai anche scritto:
(alla persona creata non può piacere il proprio post).
Questo non è ancora applicato nell'implementazione sopra. Potresti usare un grilletto .
O una di queste soluzioni più veloci / più affidabili:
Solido per un costo
Se ha bisogno di essere solido come una roccia , si potrebbe estendere l'FK da likes
a post
per includere il author_id
ridondante. Quindi puoi escludere l'incesto con un semplice CHECK
vincolo.
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)
);
Ciò richiede un UNIQUE
vincolo altrimenti anche ridondante in post
:
ALTER TABLE post ADD CONSTRAINT post_for_fk_uni UNIQUE (author_id, post_id);
Ho messo per author_id
primo a fornire un indice utile pur essendoci.
Risposta correlata con altro:
Più economico con un CHECK
vincolo
Sulla base della "Implementazione di base" sopra.
CHECK
i vincoli sono fatti per essere immutabili. Fare riferimento ad altre tabelle per un controllo non è mai immutabile, stiamo abusando un po 'del concetto qui. Suggerisco di dichiarare il vincolo NOT VALID
per riflettere adeguatamente quello. Dettagli:
Un CHECK
vincolo sembra ragionevole in questo caso particolare, perché l'autore di un post sembra un attributo che non cambia mai. Non consentire gli aggiornamenti a quel campo per essere sicuri.
Abbiamo finto una IMMUTABLE
funzione di:
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;
Sostituisci "pubblico" con lo schema reale delle tue tabelle.
Utilizzare questa funzione in un CHECK
vincolo:
ALTER TABLE likes ADD CONSTRAINT no_self_like_chk
CHECK (f_author_id_of_post(post_id) <> person_id) NOT VALID;