Burada döngüsel bir şey görmüyorum. Orada insanlar ve mesajlar bu varlıklar arasındaki iki bağımsız ilişkiler. Beğenileri bu ilişkilerden birinin uygulanması olarak görüyorum .
- Bir kişi birçok yazı yazabilir, bir yazı bir kişi tarafından yazılır:
1:n
- Bir kişi bir post çok beğenilmiş olabilir, birçok mesajları beğenebilir:
n:m
n: m ilişki başka ilişki ile uygulanabilir: likes.
Temel uygulama
Temel uygulama PostgreSQL'de şöyle görünebilir :
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)
);
Özellikle, bir gönderinin bir yazarının ( ) olması gerektiğineNOT NULL dikkat edin, beğenilerin varlığı isteğe bağlıdır. Ancak mevcut beğeniler için postve person her ikisine de başvurulması gerekir ( PRIMARY KEYher iki sütunu NOT NULLotomatik olarak yapan tarafından zorunlu kılınmalıdır (bu kısıtlamaları açıkça, gereksiz olarak ekleyebilirsiniz), böylece anonim beğeniler de imkansızdır.
N: m uygulaması için ayrıntılar:
Kendine benzemeyi önle
Ayrıca şunu da yazdınız:
(yaratılan kişi kendi görevinden hoşlanamaz).
Bu yukarıdaki uygulamada henüz uygulanmıyor. Bir tetikleyici kullanabilirsiniz .
Veya bu daha hızlı / daha güvenilir çözümlerden biri:
Bir maliyet için kaya gibi sağlam
Kaya gibi sağlam olması gerekiyorsa , FK'yi fazladan dahil likesetmek postiçin genişletebilirsiniz author_id. O zaman ensesti basit bir CHECKkısıtlamayla dışlayabilirsiniz.
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)
);
Bu , başka bir şekilde de gereksiz UNIQUEkısıtlama gerektirirpost :
ALTER TABLE post ADD CONSTRAINT post_for_fk_uni UNIQUE (author_id, post_id);
author_idİlk sırada, yararlı bir dizin sağlamak için koydum .
Daha fazlası ile ilgili cevap:
CHECKKısıtlı olarak daha ucuz
Yukarıdaki "Temel uygulama" üzerine inşa.
CHECKkısıtlamalar değişmezdir. Bir kontrol için diğer tablolara başvurmak asla değişmez değildir, burada kavramı biraz kötüye kullanıyoruz. Bunu NOT VALIDdoğru bir şekilde yansıtması için kısıtlamayı beyan etmenizi öneririm . Detaylar:
CHECKBu özel durumda bir kısıtlama makul görünmektedir, çünkü bir yazının yazarı asla değişmeyen bir özellik gibi görünmektedir. Emin olmak için bu alandaki güncellemelere izin vermeyin.
Bir işlevi taklit ediyoruz IMMUTABLE:
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;
'Herkese açık' ifadesini tablolarınızın gerçek şemasıyla değiştirin.
Bu işlevi bir CHECKkısıtlamayla kullanın :
ALTER TABLE likes ADD CONSTRAINT no_self_like_chk
CHECK (f_author_id_of_post(post_id) <> person_id) NOT VALID;