Bu senaryo için uygun yapı bir Alt Sınıf / Kalıtım modelidir ve bu cevapta önerdiğim kavramla hemen hemen aynıdır: Heterojen sıralı değer listesi .
Bu soruda önerilen model, Animal
varlığın tür (yani race
) ve tüm türlerde ortak olan özellikleri içermesi bakımından oldukça yakındır . Ancak, gereken iki küçük değişiklik vardır:
Cat_ID ve Dog_ID alanlarını ilgili varlıklarından kaldırın:
Burada anahtar kavram olmasıdır herşey bir olduğu Animal
bakılmaksızın, race
: Cat
, Dog
, Elephant
, vb. Başlangıç noktası, herhangi bir göz önüne alındığında race
ait Animal
gerçekten bu yana ayrı bir tanımlayıcı gerekmez:
Animal_ID
benzersizdir
Cat
, Dog
ve herhangi bir ek race
gelecekte eklenen kişiler, kendileri tarafından, tamamen herhangi bir temsil yok Animal
; yalnızca ana kuruluşta yer alan bilgilerle birlikte kullanıldığında bir anlamı vardır Animal
.
Dolayısıyla, Animal_ID
mülkiyet içinde Cat
, Dog
vb kişiler PK ve FK geri hem Animal
varlık.
Aşağıdakileri ayırt edin breed
:
İki özelliğin aynı adı paylaşması, adın aynı olması böyle bir ilişkiyi ima etse bile, bu özelliklerin aynı olduğu anlamına gelmez . Bu durumda, gerçekten sahip olduğunuz şey aslında ve ayrı "türler"CatBreed
DogBreed
İlk Notlar
- SQL, Microsoft SQL Server'a özgüdür (yani T-SQL'dir). Yani, tüm RDBMS'lerde aynı olmadıkları için veri türlerine dikkat edin. Örneğin, kullanıyorum
VARCHAR
ama standart ASCII setinin dışında bir şey saklamanız gerekiyorsa, gerçekten kullanmalısınız NVARCHAR
.
- "Tip" tabloları kimlik alanları (
Race
, CatBreed
ve DogBreed
) vardır değil onlar statik arama değerlerdir uygulama sabitleri (yani onlar uygulamanın parçası) olduğu için otomatik artan (T-SQL açısından yani KİMLİĞİNİ) veritabanıdır ve enum
C # (veya diğer dillerde) olarak gösterilir. Değerler eklenirse, kontrollü durumlarda eklenir. Uygulama aracılığıyla gelen kullanıcı verileri için otomatik artış alanlarının kullanımını saklıyorum.
- Kullandığım adlandırma kuralı, ana sınıf adından sonra alt sınıf adından başlayarak her alt sınıf tablosunu adlandırmaktır. Bu, tabloların düzenlenmesine yardımcı olur ve alt sınıf tablosunun ana varlık tablosuyla ilişkisini açıkça (FK'lere bakmadan) gösterir.
- Views ile ilgili not için lütfen sondaki "Son Düzenleme" bölümüne bakın.
"Irk" olarak "Cins" - Spesifik Yaklaşım
Bu ilk tablo kümesi arama / tür tablolarıdır:
CREATE TABLE Race
(
RaceID INT NOT NULL PRIMARY KEY
RaceName VARCHAR(50) NOT NULL
);
CREATE TABLE CatBreed
(
CatBreedID INT NOT NULL PRIMARY KEY,
BreedName VARCHAR(50),
CatBreedAttribute1 INT,
CatBreedAttribute2 VARCHAR(10)
-- other "CatBreed"-specific properties as needed
);
CREATE TABLE DogBreed
(
DogBreedID INT NOT NULL PRIMARY KEY,
BreedName VARCHAR(50),
DogBreedAttribute1 TINYINT
-- other "DogBreed"-specific properties as needed
);
Bu ikinci liste ana "Hayvan" varlığıdır:
CREATE TABLE Animal
(
AnimalID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
RaceID INT NOT NULL, -- FK to Race
Name VARCHAR(50)
-- other "Animal" properties that are shared across "Race" types
);
ALTER TABLE Animal
ADD CONSTRAINT [FK_Animal_Race]
FOREIGN KEY (RaceID)
REFERENCES Race (RaceID);
Tablolar bu üçüncü seti her tanımını tamamlamak ücretsiz alt sınıf varlıklardır Race
arasında Animal
:
CREATE TABLE AnimalCat
(
AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
CatBreedID INT NOT NULL, -- FK to CatBreed
HairColor VARCHAR(50) NOT NULL
-- other "Cat"-specific properties as needed
);
ALTER TABLE AnimalCat
ADD CONSTRAINT [FK_AnimalCat_CatBreed]
FOREIGN KEY (CatBreedID)
REFERENCES CatBreed (CatBreedID);
ALTER TABLE AnimalCat
ADD CONSTRAINT [FK_AnimalCat_Animal]
FOREIGN KEY (AnimalID)
REFERENCES Animal (AnimalID);
CREATE TABLE AnimalDog
(
AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
DogBreedID INT NOT NULL, -- FK to DogBreed
HairColor VARCHAR(50) NOT NULL
-- other "Dog"-specific properties as needed
);
ALTER TABLE AnimalDog
ADD CONSTRAINT [FK_AnimalDog_DogBreed]
FOREIGN KEY (DogBreedID)
REFERENCES DogBreed (DogBreedID);
ALTER TABLE AnimalDog
ADD CONSTRAINT [FK_AnimalDog_Animal]
FOREIGN KEY (AnimalID)
REFERENCES Animal (AnimalID);
Paylaşılan bir breed
tür kullanan model "Ek Notlar" bölümünden sonra gösterilir.
ek Notlar
- Kavramı,
breed
karışıklık için bir odak noktası gibi görünmektedir. Farklı sorular arasında breed
paylaşılan bir özellik olan jcolebrand (soru üzerine bir yorumda) önerildi race
ve diğer iki cevap, modellerinde olduğu gibi entegre edildi. Ancak bu bir hatadır, çünkü için değerler breed
farklı değerlerinde paylaşılmaz race
. Evet, önerilen diğer iki modelin race
bir ebeveyn yaparak bu sorunu çözmeye çalıştığının farkındayım breed
. Bu, teknik olarak ilişki sorununu çözerken, ortak olmayan özellikler hakkında ne yapılması gerektiği veya race
sahip olmayan bir şeyin nasıl ele alınacağıyla ilgili genel modelleme sorununun çözülmesine yardımcı olmaz breed
. Ancak, böyle bir mülkün tümünde varlığının garanti edilmesi durumundaAnimal
s, bunun için de bir seçenek ekleyeceğim (aşağıda).
- Vijayp ve DavidN (aynı gibi görünüyor) tarafından önerilen modeller çalışmıyor çünkü:
- Onlar da
- ortak olmayan mülklerin depolanmasına izin vermeyin (en azından herhangi bir örnek için ayrı ayrı
Animal
) veya
- tüm
race
s için tüm özelliklerin, Animal
bu verileri temsil etmenin çok düz (ve neredeyse ilişkisel olmayan) bir yol olan varlıkta depolanmasını gerektirir . Evet, insanlar bunu her zaman yaparlar, ancak bu, belirli bir alan için tasarlanmamış özellikler için satır başına birçok NULL alana sahip olmak anlamına gelir race
VE satır başına hangi alanların belirli bir race
kayıtla ilişkili olduğunu bilmek .
- Onlar eklemek için izin vermez
race
ait Animal
yoktur gelecekte breed
bir özellik olarak. Ve TÜM bile Animal
ler bir var breed
, yani nedeniyle daha önce hakkında kaydedilmiştir ne yapısını değiştirmek olmaz breed
: breed
bağlıdır race
(yani breed
için Cat
aynı şey değildir breed
için Dog
).
Ortak- / Paylaşılan- Mülkiyet Yaklaşımı olarak "Cins"
Lütfen aklınızda bulundurun:
Aşağıdaki SQL, yukarıda sunulan modelle aynı veritabanında çalıştırılabilir:
Race
Tablo aynıdır
Breed
Masa yenidir
- Üç
Animal
tabloya bir tablo eklenmiştir.2
Breed
Şimdi ortak bir mülk olsa bile Race
, ana / ana kuruluşta not etmemek doğru görünmemektedir (teknik olarak ilişkisel olarak doğru olsa bile). Yani, hem RaceID
ve BreedID
temsil edilir Animal2
. Farklı bir için RaceID
belirtilen Animal2
ve a arasında bir uyumsuzluğu önlemek BreedID
için RaceID
, her ikisi RaceID, BreedID
de Breed
tablodaki bu alanların BENZERSİZ BİR KABUL referans veren bir FK ekledim . Genellikle bir FK'yi BENZERSİZ BİR KISITLAMAYA işaret etmeyi hor görürüm, ancak işte bunun birkaç geçerli nedeninden biri. BENZERSİZ BİR KISIT mantıksal olarak bu kullanım için geçerli kılan bir "Alternatif Anahtar" dır. Lütfen Breed
tablonun hala üzerinde bir PK olduğunu unutmayın BreedID
.
- Birleştirilmiş alanlarda sadece PK ile gitmemenizin ve BENZERSİZ BİR KISITLAMANIN olmamasının sebebi, bunun
BreedID
farklı değerlerde tekrarlanmasına izin vermesidir RaceID
.
- Hangi PK ve UNIQUE CONSTRAINT'in değiştirilmemesinin sebebi, bunun tek kullanımı olmayabilir
BreedID
, bu nedenle Breed
, RaceID
kullanılabilir olmadan belirli bir değere başvurmak mümkün olmalıdır .
- Aşağıdaki model çalışırken, paylaşılan kavramı ile ilgili iki potansiyel kusuru vardır
Breed
(ve neden Race
-özel Breed
tabloları tercih ederim ).
- TÜM değerlerinin
Breed
aynı özelliklere sahip olduğuna dair örtük bir varsayım vardır . Bu modelde Dog
"ırklar" ve Elephant
"ırklar" arasında farklı özelliklere sahip olmanın kolay bir yolu yoktur . Ancak, yine de "Son Düzenleme" bölümünde belirtilen bir yol vardır.
Breed
Birden fazla yarışı paylaşmanın bir yolu yoktur . Bunun istenip istenmediğinden emin değilim (ya da belki hayvan kavramında değil, muhtemelen bu tür bir modeli kullanacak başka durumlarda), ama burada mümkün değil.
CREATE TABLE Race
(
RaceID INT NOT NULL PRIMARY KEY,
RaceName VARCHAR(50) NOT NULL
);
CREATE TABLE Breed
(
BreedID INT NOT NULL PRIMARY KEY,
RaceID INT NOT NULL, -- FK to Race
BreedName VARCHAR(50)
);
ALTER TABLE Breed
ADD CONSTRAINT [UQ_Breed]
UNIQUE (RaceID, BreedID);
ALTER TABLE Breed
ADD CONSTRAINT [FK_Breed_Race]
FOREIGN KEY (RaceID)
REFERENCES Race (RaceID);
CREATE TABLE Animal2
(
AnimalID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
RaceID INT NOT NULL, -- FK to Race, FK to Breed
BreedID INT NOT NULL, -- FK to Breed
Name VARCHAR(50)
-- other properties common to all "Animal" types
);
ALTER TABLE Animal2
ADD CONSTRAINT [FK_Animal2_Race]
FOREIGN KEY (RaceID)
REFERENCES Race (RaceID);
-- This FK points to the UNIQUE CONSTRAINT on Breed, _not_ to the PK!
ALTER TABLE Animal2
ADD CONSTRAINT [FK_Animal2_Breed]
FOREIGN KEY (RaceID, BreedID)
REFERENCES Breed (RaceID, BreedID);
CREATE TABLE AnimalCat2
(
AnimalID INT NOT NULL PRIMARY KEY, -- FK to Animal
HairColor VARCHAR(50) NOT NULL
);
ALTER TABLE AnimalCat2
ADD CONSTRAINT [FK_AnimalCat2_Animal2]
FOREIGN KEY (AnimalID)
REFERENCES Animal2 (AnimalID);
CREATE TABLE AnimalDog2
(
AnimalID INT NOT NULL PRIMARY KEY,
HairColor VARCHAR(50) NOT NULL
);
ALTER TABLE AnimalDog2
ADD CONSTRAINT [FK_AnimalDog2_Animal2]
FOREIGN KEY (AnimalID)
REFERENCES Animal2 (AnimalID);
Son Düzenleme (umarım ;-)
- Türleri arasındaki farklı özelliklere taşıma olasılığı (ve daha sonra güçlük) ile ilgili olarak
Breed
, ise aynı alt / devralma kavramı fakat kullanılması mümkündür Breed
ana birim olarak. Bu kurulumda, Breed
tablo tüm türler Breed
( Animal
tablo gibi) için ortak özelliklere sahip RaceID
olacak ve türünü gösterecektir Breed
( Animal
tabloda olduğu gibi). Sonra gibi alt sınıf tablolar olurdu BreedCat
, BreedDog
vb. Daha küçük projeler için bu , "aşırı mühendislik" olarak düşünülebilir, ancak bundan faydalanabilecek durumlar için bir seçenek olarak belirtilmektedir.
Her iki yaklaşım için de bazen Görünümleri tam varlıklar için kısayollar olarak oluşturmaya yardımcı olur. Örneğin:
CREATE VIEW Cats AS
SELECT an.AnimalID,
an.RaceID,
an.Name,
-- other "Animal" properties that are shared across "Race" types
cat.CatBreedID,
cat.HairColor
-- other "Cat"-specific properties as needed
FROM Animal an
INNER JOIN AnimalCat cat
ON cat.AnimalID = an.AnimalID
-- maybe add in JOIN(s) and field(s) for "Race" and/or "Breed"
- Mantıksal varlıkların bir parçası olmasa da, en azından kayıtların ne zaman eklendiğini ve güncellendiğini anlamak için tablolarda denetim alanlarının olması oldukça yaygındır. Yani pratik açıdan:
- Tabloya bir
CreatedDate
alan eklenir Animal
. AnimalCat
Her iki tablo için eklenen satırların bir işlem içinde aynı anda yapılması gerektiğinden , bu alan alt sınıf tablolarının hiçbirinde (örneğin ) gerekli değildir .
- Tabloya ve tüm alt sınıf tablolarına bir
LastModifiedDate
alan eklenir Animal
. Bu alan yalnızca söz konusu tablo güncellenirse güncellenir: bir güncelleme gerçekleşir AnimalCat
ancak Animal
belirli bir tarih için girilmezse AnimalID
, yalnızca LastModifiedDate
alan AnimalCat
seçilir.