Nie wiem jak przekształcić zmienną jednostkę w relacyjną tabelę

9

WPROWADZENIE I ISTOTNE INFORMACJE:

Poniższy przykład ilustruje problem, przed którym stoję:

Zwierzę ma rasę, którą może być kot lub pies . Kot może być syjamski lub perski . Psem może być owczarek niemiecki lub retrader labrador .

Zwierzę jest silną istotą, podczas gdy jego rasa jest atrybutem, który może mieć jedną z dwóch oferowanych wartości (kot lub pies). Obie te wartości są złożone (dodałem tutaj tylko typ psa / kota, aby zilustrować problem, ale może również zawierać imię kota / psa i kilka innych rzeczy).

PROBLEM:

Nie wiem, jak utworzyć tabele relacyjne dla tego przykładu.

MOJE DZIAŁANIA DO ROZWIĄZANIA PROBLEMU:

Próbowałem narysować schemat ER, używając notacji Chena, która reprezentuje problem, ale będąc początkującym nie wiem, czy zrobiłem to dobrze. Oto co mam:

wprowadź opis zdjęcia tutaj

Przepraszam, jeśli narysowałem coś nie tak, popraw mnie, jeśli tak jest. Nie chcę po prostu uzyskać „darmowego rozwiązania”, ale także nauczyć się radzić sobie z tym problemem, aby móc go rozwiązać samodzielnie w przyszłości.

Jedyne, co przychodzi mi do głowy, to stworzenie dwóch osobnych tabel, jednej dla kotów i jednej dla psów. Ponadto atrybut rasy w tabeli Zwierząt przechowuje tylko wartość kota lub psa . Coś takiego:

Animal< # Animal_ID, race, other attributes >
Cat < # Cat_ID, $ Animal_ID, breed >
Dog < # Dog_ID, $ Animal_ID, breed >

Naprawdę mam złe przeczucia co do mojego rozwiązania i obawiam się, że jest to złe, stąd poniższe pytanie.

PYTANIA:

  • Jak mogę przekształcić mój przykład w diagram ER?
  • Jak przekształcić ten diagram ER w tabele relacyjne?

Jeśli wymagane są dalsze informacje, zostaw komentarz, a ja zaktualizuję swój post jak najszybciej. Dodaj też odpowiednie tagi, ponieważ jestem tutaj dość nowy.

Dziękuję Ci.

AlwaysLearningNewStuff
źródło
1
Przekształcenie diagramów EER w tabele można znaleźć w tym artykule z 1986 r. TJTeorey, D.Yang, JPFry: A Logical Design Methodology for Relational Database using a Extended Entity-Relationship Model . Jest to prosty i jeden z moich ulubionych artykułów.
miracle173

Odpowiedzi:

11

Właściwą strukturą dla tego scenariusza jest model SubClass / Dziedziczenie i jest on prawie identyczny z koncepcją zaproponowaną w tej odpowiedzi: Heterogeniczna uporządkowana lista wartości .

Model zaproponowany w tym pytaniu jest właściwie dość podobny , ponieważ Animaljednostka zawiera typ (tj. race) I właściwości wspólne dla wszystkich typów. Konieczne są jednak dwie niewielkie zmiany:

  1. Usuń pola Cat_ID i Dog_ID z odpowiednich encji:

    Kluczowym założeniem jest to, że wszystko to Animal, bez względu na race: Cat, Dog, Elephant, i tak dalej. Biorąc pod uwagę, że punkt wyjścia, każde szczególności racez Animalnie naprawdę potrzebny jest oddzielny identyfikator, ponieważ:

    1. Animal_IDjest wyjątkowy
    2. te Cat, Dogoraz wszelkie inne racepodmioty, dodane w przyszłości nie przez siebie, w pełni reprezentować jakiś konkretny Animal; mają jedynie znaczenie, gdy używany w połączeniu z informacjami zawartymi w jednostce dominującej Animal.

    Stąd Animal_IDnieruchomość w Cat, Dogitp podmiotów jest zarówno PK i FK powrotem do Animaljednostki.

  2. Rozróżnij rodzaje breed:

    To, że dwie właściwości mają tę samą nazwę, niekoniecznie oznacza, że są one takie same, nawet jeśli ta sama nazwa implikuje taki związek. W tym przypadku, co naprawdę trzeba to faktycznie CatBreedi DogBreedjako oddzielne „typów”

Uwagi wstępne

  1. SQL jest specyficzny dla Microsoft SQL Server (tzn. Jest T-SQL). Oznacza to, że należy uważać na typy danych, ponieważ nie są one takie same we wszystkich RDBMS. Na przykład używam, VARCHARale jeśli chcesz przechowywać coś poza standardowym zestawem ASCII, powinieneś naprawdę użyć NVARCHAR.
  2. Pola ID tabel „typów” ( Race, CatBreedi DogBreed) nie są automatycznie zwiększane (tj. TOŻSAMOŚĆ w kategoriach T-SQL), ponieważ są stałymi aplikacji (tj. Są częścią aplikacji), które są statycznymi wartościami wyszukiwania w bazy danych i są reprezentowane jako enums w C # (lub innych językach). Jeśli wartości są dodawane, są one dodawane w kontrolowanych sytuacjach. Zastrzegam stosowanie pól automatycznego przyrostu dla danych użytkownika, które przychodzą za pośrednictwem aplikacji.
  3. Używam konwencji nazewnictwa, aby nazwać każdą tabelę podklasy, zaczynając od nazwy głównej klasy, po której następuje nazwa podklasy. Pomaga to uporządkować tabele, a także wyraźnie wskazuje (bez patrzenia na FK) związek tabeli podklasy z tabelą głównej encji.
  4. Zapoznaj się z sekcją „Edycja końcowa” na końcu, aby uzyskać informacje dotyczące wyświetleń.

„Rasa” jako podejście „wyścigowe”

Rasa jako schemat specyficzny dla rasy
Ten pierwszy zestaw tabel to tabele wyszukiwania / typów:

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
);

Ta druga lista to główna jednostka „Zwierząt”:

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);

Trzeci zestaw tabel to uzupełniające się podklasy, które uzupełniają definicję każdego Racez 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);

Model wykorzystujący breedtyp współdzielony pokazano po sekcji „Uwagi dodatkowe”.

Dodatkowe uwagi

  1. Koncepcja breedwydaje się być centralnym punktem zamieszania. Jcolebrand zasugerował (w komentarzu do pytania), że breedjest to właściwość wspólna dla różnych races, a pozostałe dwie odpowiedzi mają ją jako taką w swoich modelach. Jest to jednak błąd, ponieważ wartości dla breednie są współużytkowane przez różne wartości race. Tak, jestem świadomy, że dwa inne proponowane modele próbują rozwiązać ten problem, tworząc racerodzic breed. Chociaż to technicznie rozwiązuje problem relacji, nie pomaga w rozwiązaniu ogólnego pytania dotyczącego modelowania tego, co zrobić z nietypowymi właściwościami, ani jak poradzić sobie z racetym, co nie ma breed. Ale w przypadku, gdy zagwarantowano, że taka własność istniałaby we wszystkichAnimals, do tego dołączę opcję (poniżej).
  2. Modele zaproponowane przez vijayp i DavidN (które wydają się identyczne) nie działają, ponieważ:
    1. Oni też
      1. nie zezwalaj na przechowywanie nietypowych właściwości (przynajmniej nie dla poszczególnych instancji Animal), lub
      2. wymagają, aby wszystkie właściwości wszystkich races były przechowywane w Animalencji, która jest bardzo płaskim (i prawie nierelacyjnym) sposobem reprezentowania tych danych. Tak, ludzie robią to przez cały czas, ale oznacza to, że dla wielu właściwości, które nie są przeznaczone dla tego konkretnego, jest wiele pól NULL na wiersz raceORAZ wiedza, które pola na wiersz są powiązane z danym racerekordem.
    2. Oni nie pozwalają na dodanie racew Animalprzyszłości, które nie mają breedjako własność. A nawet jeśli wszystko Animals mają breed, że nie zmieni strukturę ze względu na to, co zostało wcześniej zauważono około breed: To breedzależy od race(czyli breeddla Catnie to samo, co breeddla Dog).

„Rasa” jako podejście do własności wspólnej / wspólnej

wprowadź opis zdjęcia tutaj
Proszę zanotować:

  1. Poniższy kod SQL można uruchomić w tej samej bazie danych, co model przedstawiony powyżej:

    1. RaceTabeli jest taka sama
    2. BreedTabela jest nowy
    3. Do trzech Animaltabel dołączono znak „2
  2. Nawet jeśli Breedjest to obecnie wspólna własność, nie wydaje się słuszne, aby nie Raceodnotować tego w głównej / macierzystej jednostce (nawet jeśli jest to technicznie poprawne). Oba RaceIDi BreedIDsą reprezentowane w Animal2. Aby zapobiec niedopasowaniu między RaceIDzanotowanym Animal2i a BreedIDinnym RaceID, dodałem FK na obu, RaceID, BreedIDktóry odwołuje się do UNIKALNEGO OGRANICZENIA tych pól w Breedtabeli. Zwykle nie znoszę wskazywać FK na WYJĄTKOWE OGRANICZENIE, ale oto jeden z niewielu ważnych powodów, aby to zrobić. WYJĄTKOWY OGRANICZENIE jest logicznie „kluczem alternatywnym”, co czyni go ważnym dla tego zastosowania. Należy również pamiętać, że Breedtabela wciąż ma PK tylko BreedID.
    1. Powodem, dla którego nie było tylko PK na połączonych polach i brak WYJĄTKOWEGO OGRANICZENIA jest to, że pozwoliłoby to BreedIDna powtórzenie tego samego dla różnych wartości RaceID.
    2. Powodem, dla którego PK i UNIKALNE OGRANICZENIE nie są przełączane, jest to, że może to nie być jedyne użycie BreedID, więc nadal powinno być możliwe odniesienie się do konkretnej wartości Breedbez jej RaceIDdostępności.
  3. Chociaż poniższy model działa, ma dwie potencjalne wady dotyczące koncepcji współdzielenia Breed(i dlatego wolę tabele Race-specyficzne Breed).
    1. Istnieje domniemane założenie, że WSZYSTKIE wartości Breedmają te same właściwości. W tym modelu nie ma łatwego sposobu na uzyskanie rozbieżnych właściwości między Dog„rasami” i Elephant„rasami”. Istnieje jednak sposób, aby to zrobić, co zostało odnotowane w sekcji „Edycja końcowa”.
    2. Nie ma sposobu, aby podzielić Breedsię więcej niż jedną rasą. Nie jestem pewien, czy jest to pożądane (a może nie w koncepcji zwierząt, ale być może w innych sytuacjach, w których używałby tego typu modelu), ale nie jest to możliwe tutaj.
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);


Ostateczna edycja (mam nadzieję ;-)

  1. Jeśli chodzi o możliwość (i potem) w trudność obsługi odmienne właściwości pomiędzy typów Breed, to jest możliwe stosowanie tego samego podklasy / spadku koncepcji, ale w Breedpostaci głównej jednostki. W tym ustawieniu Breedtabela miałaby właściwości wspólne dla wszystkich typów Breed(podobnie jak Animaltabela) i RaceIDreprezentowałaby typ Breed(taki sam jak w Animaltabeli). Wtedy trzeba podklasy, takie jak tabele BreedCat, BreedDogi tak dalej. W przypadku mniejszych projektów można to uznać za „nadmierną inżynierię”, ale wspomniano o niej jako o opcjach w sytuacjach, które z niej skorzystałyby.
  2. W przypadku obu podejść czasami pomaga tworzenie widoków jako skrót do pełnych elementów. Rozważ na przykład:

    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"
  3. Chociaż nie są one częścią jednostek logicznych, dość często w tabelach znajdują się pola kontroli, aby przynajmniej zorientować się, kiedy rekordy są wstawiane i aktualizowane. W praktyce:
    1. CreatedDatePola zostanie dodana do Animaltabeli. To pole nie jest potrzebne w żadnej z tabel podklasy (np. AnimalCat), Ponieważ wiersze wstawiane dla obu tabel powinny być wykonywane w tym samym czasie w ramach transakcji.
    2. LastModifiedDatePola zostanie dodana do Animaltabeli i wszystkich stołach podklasy. To pole jest aktualizowane tylko wtedy, gdy ta konkretna tabela jest aktualizowana: jeśli aktualizacja wystąpi w określonym, AnimalCatale nie Animaldla określonego AnimalID, to ustawione zostanie tylko LastModifiedDatepole w AnimalCat.
Solomon Rutzky
źródło
2
Jakoś mam wrażenie, że zrozumiałeś dokładnie, na czym polega mój problem. Spojrzę na twoją połączoną odpowiedź i przestudiuję ją uważnie. Świetna byłaby również prosta definicja tabel (jeśli zapytania SQL są w tej chwili za dużo, aby je napisać). Jeśli zdecydujesz się zaktualizować swój post za pomocą zapytań SQL lub definicji tabel, zostaw mi komentarz. Jeszcze raz dziękuję. Z poważaniem.
AlwaysLearningNewStuff
1
Próbuję zastosować twoją odpowiedź w mojej prawdziwej sprawie. Jeśli będę ślepo postępować zgodnie z instrukcjami, uważam, że mogę stracić okazję do dalszej optymalizacji mojego projektu. Chciałbym, abyś spojrzał na moje ostatnie pytanie, ponieważ byłeś w stanie doskonale zrozumieć moje pytania i udzielić doskonałych odpowiedzi. Zadałem pytanie, aby użyć ogólnego modelu danych, aby był użyteczny również dla przyszłych czytelników. Jeśli masz problem ze znalezieniem go, zostaw mi komentarz. Dziękuję i przepraszam, że przeszkadzam ...
AlwaysLearningNewStuff
@AlwaysLearningNewStuff Cześć. Dostałem tę wiadomość wcześniej, ale nie miałem czasu, aby się do niej od razu dostać. Udało mi się znaleźć nowe Pytanie, klikając swoje imię powyżej i pokazuje wszystkie Twoje pytania :-).
Solomon Rutzky
Miałem na myśli to pytanie . W skrócie: Mam 3 byty ze wspólnym atrybutem D, dlatego chciałem zastosować metodę z twojej odpowiedzi. Dwie jednostki mają wspólny atrybut, Ektóry nie występuje w trzeciej jednostce. Czy powinienem zignorować ten fakt i zastosować standardowe rozwiązanie, czy też istnieje sposób na dalszą optymalizację mojego projektu?
AlwaysLearningNewStuff
4

Po pierwsze, dobrze sobie radzisz z rozróżnianiem między modelowaniem ER a modelowaniem relacyjnym. Wielu początkujących nie.

Oto kilka modnych słów, których możesz użyć do wyszukiwania pomocnych artykułów w Internecie.

Twój przypadek jest klasycznym przypadkiem klasy / podklasy lub, jeśli chcesz, wpisz / podtyp.

Fraza używana w modelowaniu ER to „uogólnienie / specjalizacja”. Wiele artykułów pokazuje to pod modelowaniem zwanym EER (Enhanced Entity-Relationship). Nie było to w oryginalnej prezentacji modelowania ER przez Petera Chena. Został dodany później. Aby uzyskać całkiem dobre podsumowanie gen / spec w formacie pdf, kliknij tutaj

Następnie, konwertując przypadek klasy / podklasy na modelowanie relacyjne, projektujesz tabele. Istnieje więcej niż jedno podejście. Dwa główne podejścia nazywane są dziedziczeniem pojedynczej tabeli i dziedziczeniem tabeli klas. Każda ma zalety i wady. Najlepsza prezentacja tych dwóch wzorów pochodzi od Martina Fowlera. Możesz zobaczyć jego zarys tutaj i tutaj .

Dużą zaletą dziedziczenia pojedynczego stołu jest prostota. Wszystko jest przechowywane w jednym stole. Dużą wadą jest wiele wartości NULLS. Może to marnować miejsce i czas i powodować mylącą logikę.

Dziedziczenie tabeli klas wymaga złączeń, ale są one proste i szybkie. Zwłaszcza jeśli używasz techniki zwanej wspólnym kluczem podstawowym, w której PK w tabelach podklasy jest kopią PK w tabeli nadklasy. Można tworzyć widoki dla każdej podklasy, która łączy dane nadklasy z danymi podklasy.

Wreszcie w tym obszarze znajduje się tag, który zbiera pytania podobne do twoich.
Oto on:

Walter Mitty
źródło
1
+1 To, co mnie dezorientuje, to brak kluczy podstawowych na schematach tabel. Szczególnie w „classTableInheritance” nie widzę, aby wszystkie te tabele były połączone tym samym kluczem podstawowym.
miracle173
@ miracle173 ważny punkt. Z jakiegoś powodu Fowler nie uwzględnia PK i FK na schemacie. Istnieją inne artykuły w dziedziczeniu tabeli klas, które podają ten szczegół. Nie wszystkie implementacje dziedziczenia tabeli klas łączą go ze wspólnym kluczem podstawowym. Polecam to. To trochę więcej pracy w czasie wstawiania, ale łatwiej i szybciej w połączonym czasie pobierania.
Walter Mitty
3

Widzę możliwy projekt jako

Stół Race

RaceId- PK- Int
RaceName - Varchar(50)

Stół Breed

BreedId - PK- Int
RaceId - FK - Int
BreedName - varchar(50)

Stół Animal

AnimalId - PK- Int
BreedId - FK - Int
Other Columns....

Te wartości PK powyżej byłyby kolumną automatycznego zwiększania wartości. Inne kolumny w Animaltabeli można odpowiednio nazwać.

wprowadź opis zdjęcia tutaj

vijayp
źródło
Dodatkowo dodam pola z kluczami rasy i typu (mogą być wyzwalaczami) w tabeli zwierząt, aby ułatwić późniejsze indeksy w celu zwiększenia prędkości.
Felipe Alcacibar
0

Twoja obecna metoda nie jest zła. Jeśli jednak planujesz później dodać więcej ras (ptaków, ryb itp.), Utworzenie osobnej tabeli dla każdej z nich może być kłopotliwe. Poleciłbym coś takiego:

Animal < # Animal_ID, Breed_ID, other attributes >
Breed < # Breed_ID, Race_ID >
Race < # Race_ID >

Według mnie rasa powinna mieć tylko jedną rasę. Jeśli więc zapiszesz rasę w tabeli zwierząt, będziesz mógł określić rasę, dołączając do tabeli rasy. Oczywiście dodaj dowolne inne atrybuty (imię, opis itp.) Do tabel Rasy i Wyścigu, jeśli to konieczne.

DavidN
źródło