Saya tidak melihat apa pun menjadi siklik di sini. Ada orang dan pos dan dua hubungan independen antara entitas ini. Saya akan melihat suka sebagai implementasi dari salah satu hubungan ini.
- Seseorang dapat menulis banyak posting, sebuah posting ditulis oleh satu orang:
1:n
- Seseorang bisa seperti banyak posting, posting dapat disukai oleh banyak orang:
n:m
The n: Hubungan m dapat diimplementasikan dengan relasi lain: likes
.
Implementasi dasar
Implementasi dasar dapat terlihat seperti ini di 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)
);
Perhatikan khususnya bahwa pos harus memiliki penulis ( NOT NULL
), sedangkan keberadaan suka adalah opsional. Untuk orang seperti yang ada, bagaimanapun, post
dan person
harus baik direferensikan (ditegakkan oleh PRIMARY KEY
yang membuat kedua kolom NOT NULL
secara otomatis (Anda bisa menambahkan kendala tersebut secara eksplisit, berlebihan) sehingga orang-orang seperti anonim juga tidak mungkin.
Detail untuk implementasi n: m:
Cegah seperti diri sendiri
Anda juga menulis:
(orang yang dibuat tidak dapat menyukai posnya sendiri).
Itu belum diberlakukan dalam implementasi di atas, belum. Anda bisa menggunakan pemicu .
Atau salah satu dari solusi yang lebih cepat / lebih andal ini:
Rock-solid dengan biaya
Jika perlu rock-solid , Anda bisa memperpanjang FK dari likes
ke post
untuk menyertakan author_id
berlebihan. Kemudian Anda bisa mengesampingkan inses dengan CHECK
kendala sederhana .
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)
);
Ini membutuhkanUNIQUE
kendala yang sebaliknya juga berlebihan dalam post
:
ALTER TABLE post ADD CONSTRAINT post_for_fk_uni UNIQUE (author_id, post_id);
Saya menempatkan author_id
pertama untuk menyediakan indeks yang bermanfaat saat berada di sana.
Jawaban terkait dengan lebih banyak:
Lebih murah dengan CHECK
kendala
Membangun "Implementasi dasar" di atas.
CHECK
kendala dimaksudkan untuk tidak berubah. Merujuk tabel lain untuk pemeriksaan tidak pernah berubah, kami sedikit menyalahgunakan konsep ini di sini. Saya menyarankan untuk mendeklarasikan kendala NOT VALID
untuk mencerminkan hal itu dengan benar. Detail:
Sebuah CHECK
kendala tampaknya masuk akal dalam kasus ini, karena penulis posting tampaknya seperti atribut yang tidak pernah berubah. Larang pembaruan ke bidang itu untuk memastikan.
Kami palsu sebuah IMMUTABLE
fungsi:
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;
Ganti 'publik' dengan skema sebenarnya dari tabel Anda.
Gunakan fungsi ini dalam CHECK
batasan:
ALTER TABLE likes ADD CONSTRAINT no_self_like_chk
CHECK (f_author_id_of_post(post_id) <> person_id) NOT VALID;