Görünüme Yönelik Yabancı Bir Anahtar'a izin veren DBMS var mı (yalnızca temel tabloları değil)?


22

Bir Django modelleme sorusundan esinlenildi: Django'da çoktan çoğa ilişkilerle Veri Tabanı Modellemesi . Db-design şöyle bir şey:

CREATE TABLE Book
( BookID INT NOT NULL
, BookTitle VARCHAR(200) NOT NULL
, PRIMARY KEY (BookID)
) ;

CREATE TABLE Tag
( TagID INT NOT NULL
, TagName VARCHAR(50) NOT NULL
, PRIMARY KEY (TagID)
) ;

CREATE TABLE BookTag
( BookID INT NOT NULL
, TagID INT NOT NULL
, PRIMARY KEY (BookID, TagID)
, FOREIGN KEY (BookID)  REFERENCES Book (BookID)
, FOREIGN KEY (TagID)   REFERENCES Tag (TagID)
) ;

CREATE TABLE Aspect
( AspectID INT NOT NULL
, AspectName VARCHAR(50) NOT NULL
, PRIMARY KEY (AspectID)
) ;

CREATE TABLE TagAspect
( TagID INT NOT NULL
, AspectID INT NOT NULL
, PRIMARY KEY (TagID, AspectID) 
, FOREIGN KEY (TagID)   REFERENCES Tag (TagID)
, FOREIGN KEY (AspectID)  REFERENCES Aspect (AspectID)
) ;

db diyagramı

ve mesele, BookAspectRatingtablonun nasıl tanımlanacağı ve referans bütünlüğünün güçlendirilmesidir, bu nedenle (Book, Aspect)geçersiz olan bir kombinasyon için derecelendirme eklenemez .

Alt sorguları içeren ve bunu çözebilecek birden fazla tablo içeren karmaşık CHECKkısıtlamalar (veya ASSERTIONS) AFAIK hiçbir DBMS'de mevcut değildir.

Başka bir fikir bir görünüm kullanmaktır (sözde kodu):

CREATE VIEW BookAspect_view
  AS
SELECT DISTINCT
    bt.BookId
  , ta.AspectId
FROM 
    BookTag AS bt
  JOIN 
    Tag AS t  ON t.TagID = bt.TagID
  JOIN 
    TagAspect AS ta  ON ta.TagID = bt.TagID 
WITH PRIMARY KEY (BookId, AspectId) ;

ve yukarıdaki görünüme yabancı anahtar içeren bir tablo:

CREATE TABLE BookAspectRating
( BookID INT NOT NULL
, AspectID INT NOT NULL
, PersonID INT NOT NULL
, Rating INT NOT NULL
, PRIMARY KEY (BookID, AspectID, PersonID)
, FOREIGN KEY (PersonID)   REFERENCES Person (PersonID)
, FOREIGN KEY (BookID, AspectID) 
    REFERENCES BookAspect_view (BookID, AspectID)
) ;

Üç soru:

  • (Büyük olasılıkla hayata) izin orada DBMS misiniz VIEWbir ile PRIMARY KEY?

  • Bir izin orada DBMS Are FOREIGN KEYo REFERENCESbir VIEW(ve sadece bir üs TABLE)?

  • Bu bütünlük sorunu başka türlü çözülebilir mi - mevcut DBMS özellikleriyle?


Açıklama:

Muhtemelen% 100 tatmin edici bir çözüm olmadığı için - ve Django sorusu benim bile değil! - Ben daha ayrıntılı bir çözüm değil, soruna olası bir genel saldırı stratejisiyle daha fazla ilgileniyorum. Bu nedenle, "DBMS-X'te bu, A tablosundaki tetikleyicilerle yapılabilir" gibi bir cevap tamamen kabul edilebilir.


İlk iki sorunuza yorum olarak gönderin - ve zaten sizin bildiğinizden, zaten farkında olduğunuzdan emin olmadığınız gibi - ancak SQL Server, görünümler için birincil veya yabancı anahtarları desteklemiyor.
Aaron Bertrand

@Aaron: evet, teşekkür ederim. Oracle'ın görünümlerde PK maliyetlerini desteklediğini okudum. Ancak bu durumda işe yarayacağından emin değilim. Ve ikinci sorunun cevabı (FK'lerin görüşlerine dair) Oracle'da muhtemelen olumsuzdur.
ypercubeᵀᴹ

Ama başka bir çözüm olup olmadığını öğrenmekle ilgileniyorum (tetikleyiciler, Maliyet kontrollerini veya diğer birleşik girişleri kontrol et)
ypercubeᵀᴹ

Yanıtlar:


9

Bu iş kuralı, modelde sadece kısıtlamalar kullanarak uygulanabilir. Aşağıdaki tablo sorununuzu çözmelidir. Görünümünüz yerine kullanın:

    CREATE TABLE BookAspectCommonTagLink
    (  BookID INT NOT NULL
    , AspectID INT NOT NULL
    , TagID INT NOT NULL
--TagID is deliberately left out of PK
    , PRIMARY KEY (BookID, AspectID)
    , FOREIGN KEY (BookID, TagID) 
        REFERENCES BookTag (BookID, TagID)
    , FOREIGN KEY (AspectID, TagID) 
        REFERENCES AspectTag (AspectID, TagID)
    ) ;

Oh iyi. Düşünebildiğim tek sorun, BookTags ve TagAspects eklerken / silerken ortaya çıkan karmaşıklık. Örneğin, her yeni bir BookTag (veya TagAspect) çıkarıldığında, bu tablodaki ilgili satırları kaldırmak ve / veya TagIDaynı BookAspect kombinasyonuyla ilişkili olan başka bir Tag olarak değiştirmek için bir arama yapılması gerekir .
ypercubeᵀᴹ

Ve bu iki tabloya eklemek için benzer bir arama yapılması gerekecekti. Ancak karmaşık kurallar karmaşık prosedürler gerektirir, bu yüzden bu gerçekten iyi görünüyor.
ypercubeᵀᴹ

@ypercube Bir etiketi sildiğinizde, aynı Kitabı ve Yönü birbirine bağlayan başka bir etikete bakmanız ve kontrol etmeniz gerekir. Ancak yeni etiketler eklediğinizde, bir derecelendirme eklemeniz gerekene kadar herhangi bir kontrol yapmanız gerekmez.
AK

1
Sorun giderici ve veri girişi kişisi aynı kişi ise veya hata iletisini son kullanıcıya gösterirseniz emin olun. Her şeyi yaptığınız tek kişilik dükkanlar hakkında çok fazla düşünüyorsunuz.
Aaron Bertrand

4
@AaronBertrand Sadece bana büyük bir iyilik yaptın. "Düşük Bakım Veritabanlarının Geliştirilmesi" başlıklı bir makaleyi bitirdim ve uygulama sunucularının veritabanlarından gelen orijinal hata mesajlarını kaydetmesi gerektiğini söylemeyi unuttum. Yeni ekledim. Hatırlattığın için teşekkür ederim;)
AK

8

Bir çok durumda, karmaşık iş kurallarının yalnızca model yoluyla uygulanamayacağını düşünüyorum. Bu, en azından SQL Server'da bir tetikleyicinin (tercihen tetikleyici yerine) amacınıza daha iyi hizmet edebileceğini düşündüğüm durumlardan biri.


Hey Aaron, neden bu durumda bir tetikleyicinin bir varlıktan ve birkaç kısıtlamadan daha iyi bir seçim olduğunu açıklayabilir misiniz?
AK

2
@AlexKuznetsov Tabii, 17 saatimi bunun çoklu çok sütunlu yabancı anahtarlarla ve bununla birlikte doğrulama ve hata işlemesiyle uğraşmak için gerekli olabilecek tüm ekstra mantıkları kullanmayı düşünerek geçirmedim.
Aaron Bertrand

2
Saf bir tetikleyici uygulamasının sunabileceği yarış koşullarına dikkat edin. Örneğin, bir işlem bir kitabın etiketiyle olan bağlantısını kesebilir ve bir diğeri, sadece ilk işlem henüz işleme koyulmadığından, ilgili yöne bağlanmanın tamam olduğunu düşünüyor. @AlexKuznetsov cevabının getirdiği karmaşıklıklar muhtemelen, tetikleyicilerdeki yarış koşullarını önlemek için gerekli olan kilitleme "protokolünün" karmaşıklığından ve kırılganlığından daha azdır, IMHO.
Branko Dimitrijevic

8

Oracle'da, bu tür bir kısıtlamayı bildirimsel bir şekilde uygulamaya koymanın bir yolu, sorgusu tüm geçersiz satırları (yani BookAspectRating, eşleşmeyen satırlar) tanımlayan taahhütte hızlı bir şekilde yenilemek üzere ayarlanmış bir görünüm oluşturmaktır BookAspect_view. Ardından, maddileştirilmiş görünümde herhangi bir satır varsa ihlal edilecek maddileşmiş görünüm üzerinde önemsiz bir kısıtlama yaratabilirsiniz. Bu, maddileştirilmiş görünümde çoğaltmanız gereken veri miktarını en aza indirme avantajına sahiptir. Ancak, bu sorunlara neden olabilir, çünkü kısıtlama yalnızca işlemi gerçekleştirdiğiniz noktada uygulanmaktadır - birçok uygulama bir taahhüt işleminin başarısız olacağını beklemek için yazılmamıştır - ve kısıtlama ihlali biraz zor olabilir. belirli bir satır veya belirli bir tabloyla ilişkilendirmek için.


4

SIRA_PRISE buna izin veriyor.

FK artık “FK” olarak adlandırılmamasına rağmen, sadece “veritabanı kısıtlaması” ve “görünüm” aslında bir görünüm olarak tanımlanmak zorunda kalmasa da, sadece ifadenin tanımına ifadeyi tanımlayan görünümü dahil edebilirsiniz. veritabanı kısıtlaması.

Kısıtın gibi bir şey olurdu

SEMIMINUS(BOOKASPECT , JOIN(BOOKTAG , TAGASPECT))

ve bitti.

Bununla birlikte çoğu SQL DBMS'de, analiz çalışmasını kısıtlamanız üzerinde yapmanız, nasıl ihlal edilebileceği ve gerekli tüm tetikleyicileri nasıl uygulayacağınız konusunda karar vermeniz gerekir.


Biliyorum. Yazma sırasında önemli olduğunu düşündüğüm şeyi yansıtıyor.
Erwin Smout

3

PostgreSQL'de, tetikleyicileri içermeksizin bir çözüm hayal edemiyorum, ancak kesinlikle bu şekilde çözülebilir (bir tür veya daha önce tetiklemenin somutlaştırılmış bir görüntüsünü koruyor olabilir BookAspectRating). ERROR: referenced relation "v_munkalap" is not a tableBirincil anahtar bile olsa, görünümü ( ) gösteren yabancı anahtarlar yoktur .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.