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 post
ve person
her ikisine de başvurulması gerekir ( PRIMARY KEY
her iki sütunu NOT NULL
otomatik 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 likes
etmek post
için genişletebilirsiniz author_id
. O zaman ensesti basit bir CHECK
kı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 UNIQUE
kı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:
CHECK
Kısıtlı olarak daha ucuz
Yukarıdaki "Temel uygulama" üzerine inşa.
CHECK
kı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 VALID
doğru bir şekilde yansıtması için kısıtlamayı beyan etmenizi öneririm . Detaylar:
CHECK
Bu ö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 CHECK
kı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;