Coś jak dziedziczenie w projektowaniu baz danych

Załóżmy, że tworzysz bazę danych do przechowywania danych z testów zderzeniowych różnych Pojazdów. Chcesz przechowywać dane testów zderzeniowych łodzi motorowych, samochodów i gokartów.

Można utworzyć trzy oddzielne tabele: SpeedboatTests, CarTests i GokartTests. Ale wiele twoich kolumn będzie takich samych w każdej tabeli (na przykład Identyfikator pracownika osoby, która wykonała test, kierunek kolizji (przód, bok, tył) itp.). Jednak wiele kolumn będzie inaczej, więc nie chcesz po prostu umieścić wszystkie dane testowe w jednej tabeli, ponieważ będziesz miał sporo kolumn, które zawsze będą null dla motorówek, sporo, które zawsze będą null dla samochodów, a sporo, które zawsze będą null dla gokartów.

Załóżmy, że chcesz również przechowywać informacje, które nie są bezpośrednio związane z testami (takie jak identyfikator pracownika projektanta testowanej rzeczy). Te kolumny nie wydają się właściwe, aby umieścić w tabeli "testy" w wszystkie, zwłaszcza, że będą powtarzane we wszystkich testach na tym samym pojeździe.

Pozwól, że zilustruję jeden możliwy układ tabel, abyś mógł zobaczyć związane z tym pytania.

Speedboats
id | col_about_speedboats_but_not_tests1 | col_about_speedboats_but_not_tests2

Cars
id | col_about_cars_but_not_tests1 | col_about_cars_but_not_tests2

Gokarts
id | col_about_gokarts_but_not_tests1 | col_about_gokarts_but_not_tests2

Tests
id | type | id_in_type | col_about_all_tests1 | col_about_all_tests2
(id_in_type will refer to the id column of one of the next three tables,
depending on the value of type)

SpeedboatTests
id | speedboat_id | col_about_speedboat_tests1 | col_about_speedboat_tests2

CarTests
id | car_id | col_about_car_tests1 | col_about_car_tests2

GokartTests
id | gokart_id | col_about_gokart_tests1 | col_about_gokart_tests2

Co jest dobre/złe w tej strukturze i jaki byłby preferowany sposób realizacji czegoś takiego?

A jeśli są też informacje dotyczące wszystkich pojazdów, które chcielibyście mieć w tabeli pojazdów? Czy tabelka Kartestów wtedy wygląda coś na przykład...

id | vehicle_id | ...

With a Vehicles table like this:
id | type | id_in_type
(with id_in_type pointing to the id of either a speedboat, car, or go-kart)
Wygląda na to, że to dopiero Królewski bałagan. Jak powinno się coś takiego skonfigurować?
Author: Eric Lavoie, 2009-02-16

6 answers

Konstrukcja type i id_in_type nazywa się asocjacjami polimorficznymi. Ten projekt łamie zasady normalizacji na wiele sposobów. Jeśli nic innego, powinna być czerwona flaga, że nie można zadeklarować prawdziwego ograniczenia klucza obcego, ponieważ {[2] } może odwoływać się do dowolnej z kilku tabel.

Oto lepszy sposób definiowania tabel:

  • sporządzenie abstrakcyjnej tabeli Vehicles w celu dostarczenia abstrakcyjnego punktu odniesienia dla wszystkich podtypów pojazdów i pojazdów testy.
  • każdy Podtyp pojazdu ma klucz podstawowy, który nie jest automatycznie inkrementowany, ale odwołuje się do Vehicles.
  • każdy Podtyp testowy ma klucz podstawowy, który nie jest automatycznie inkrementowany, ale odwołuje się do Tests.
  • każdy Podtyp badawczy ma również obcy klucz do odpowiedniego podtypu pojazdu.

Oto przykładowy DDL:

CREATE TABLE Vehicles (
 vehicle_id INT AUTO_INCREMENT PRIMARY KEY
);

CREATE TABLE Speedboats (
 vehicle_id INT PRIMARY KEY,
 col_about_speedboats_but_not_tests1 INT,
 col_about_speedboats_but_not_tests2 INT,
 FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id)
);

CREATE TABLE Cars (
 vehicle_id INT PRIMARY KEY,
 col_about_cars_but_not_tests1 INT,
 col_about_cars_but_not_tests2 INT,
 FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id)
);

CREATE TABLE Gokarts (
 vehicle_id INT PRIMARY KEY,
 col_about_gokarts_but_not_tests1 INT,
 col_about_gokarts_but_not_tests2 INT,
 FOREIGN KEY(vehicle_id) REFERENCES Vehicles(vehicle_id)
);

CREATE TABLE Tests (
 test_id INT AUTO_INCREMENT PRIMARY KEY,
 col_about_all_tests1 INT,
 col_about_all_tests2 INT
);

CREATE TABLE SpeedboatTests (
 test_id INT PRIMARY KEY,
 vehicle_id INT NOT NULL,
 col_about_speedboat_tests1 INT,
 col_about_speedboat_tests2 INT,
 FOREIGN KEY(test_id) REFERENCES Tests(test_id),
 FOREIGN KEY(vehicle_id) REFERENCES Speedboats(vehicle_id)
);

CREATE TABLE CarTests (
 test_id INT PRIMARY KEY,
 vehicle_id INT NOT NULL,
 col_about_car_tests1 INT,
 col_about_car_tests2 INT,
 FOREIGN KEY(test_id) REFERENCES Tests(test_id),
 FOREIGN KEY(vehicle_id) REFERENCES Cars(vehicle_id)
);

CREATE TABLE GokartTests (
 test_id INT PRIMARY KEY,
 vehicle_id INT NOT NULL,
 col_about_gokart_tests1 INT,
 col_about_gokart_tests2 INT,
 FOREIGN KEY(test_id) REFERENCES Tests(test_id),
 FOREIGN KEY(vehicle_id) REFERENCES Gokarts(vehicle_id)
);

Możesz alternatywnie zadeklarować Tests.vehicle_id które referencje Vehicles.vehicle_id i pozbyć się kluczy obcych vehicle_id w każdym teście Podtyp tabeli, ale to pozwoli na anomalie, takie jak test motorówki, który odwołuje się do identyfikatora gokarta.

 37
Author: Bill Karwin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-16 21:42:53

W przypadku mapowania hierarchii dziedziczenia do tabel baz danych, myślę, że Martin Fowler dość dobrze przedstawia alternatywy w swojej książce Patterns of Enterprise Application Architecture.

Http://martinfowler.com/eaaCatalog/singleTableInheritance.html

Http://martinfowler.com/eaaCatalog/classTableInheritance.html

Http://martinfowler.com/eaaCatalog/concreteTableInheritance.html

Jeśli liczba dodatkowych pól / kolumn jest małe dla podklas, wtedy dziedziczenie pojedynczej tabeli jest zwykle najprostsze do rozwiązania.

Jeśli używasz PostgreSQL do swojej bazy danych i chcesz związać się z funkcją specyficzną dla bazy danych, obsługuje dziedziczenie tabel bezpośrednio:

Http://www.postgresql.org/docs/8.3/static/ddl-inherit.html

 14
Author: hallidave,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-16 21:05:00

Podzieliłbym go na różne tabele, np. Vehicleattributes () VehicleID, AttributeID, Value), CrashTestInfo(VehicleID, CrashtestID, Date itp.) CrashtestAttributes (CrashTestID, AttributeID, Value)

Lub zamiast atrybutów, oddzielne tabele dla każdego zbioru podobnych szczegółów, które powinny być rejestrowane.

 0
Author: cjk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-16 21:00:39

Jeśli używasz SQLAlchemy, mapera obiektowo-relacyjnego dla Pythona, możesz skonfigurować sposób mapowania hierarchii dziedziczenia do tabel bazy danych. Mapery obiektowo-relacyjne są dobre do oswajania skądinąd żmudnego SQL.

Twój problem może dobrze pasować do tabel pionowych. Zamiast zapisywać wszystko w schemacie, przechowuj typ obiektu i klucz podstawowy w jednej tabeli oraz krotki klucz / wartość dla każdego obiektu w innej tabeli. Jeśli naprawdę przechowywałeś testy samochodów, Ta konfiguracja znacznie ułatwi dodawanie nowych rodzajów wyników.

 0
Author: joeforker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-16 21:59:39

Wykonaj wyszukiwanie w google na "gen-spec relational modeling". Znajdziesz artykuły o tym, jak skonfigurować tabele, które przechowują atrybuty jednostki uogólnionej (co programiści OO mogą nazywać superklasą), osobne tabele dla każdego z wyspecjalizowanych jednostek( podklas) oraz jak używać kluczy obcych, aby połączyć to wszystko razem.

Najlepsze artykuły, IMO, omawiają gen-spec pod względem modelowania ER. Jeśli wiesz jak przetłumaczyć model ER na model relacyjny, a następnie na SQL tabele, dowiesz się, co zrobić, gdy pokażą Ci, jak modelować Gen-spec na ostrym dyżurze.

Jeśli po prostu wygooglujesz "gen-spec", większość tego, co zobaczysz, jest zorientowana obiektowo, a nie relacyjnie. Te rzeczy mogą być również przydatne, o ile wiesz, jak przezwyciężyć niedopasowanie impedancji relacyjnej obiektu.

 -1
Author: Walter Mitty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-16 21:58:45

Twój projekt jest rozsądny i przestrzega prawidłowych zasad normalizacji. Być może brakuje tabeli pojazdów z identyfikatorem i typem pojazdu (tj. "rodzica" dla motorówek, samochodów i gokartów... gdzie można trzymać rzeczy typu "DesignedByUserId"). Między stołem pojazdu a stołem motorówek jest relacja jeden do jednego, a między pojazdem a łodzią motorową / samochodami / gokartami istnieje relacja 1-i-tylko-1 (tj. pojazd może mieć tylko 1 rekord dla łodzi motorowych, samochodów lub gokartów)... chociaż większość db nie oferuje łatwego mechanizmu egzekwowania tego.

Jedną z normalizacji, która pomaga zidentyfikować tego rodzaju rzeczy, jest to, że pole powinno zależeć tylko od klucza głównego tabeli. W skonsolidowanej tabeli, w której wyniki testów łodzi motorowych, samochodów i gokartów są przechowywane razem, pola związane z samochodami zależą nie tylko od daty testu, ale także od identyfikatora pojazdu i typu pojazdu. Głównym kluczem do tabeli wyników badań jest data badania + identyfikator pojazdu oraz pojazd Typ nie jest tym, co sprawia, że wiersz danych testowych jest unikalny (np. czy jest i tak do przeprowadzenia testu na 01/01/200912: 30pm na jednym konkretnym pojeździe, który jest zarówno motorówka i samochód... nie... nie da się zrobić).

Nie wyjaśniam dokładnie Zasady normalizacji... ale zasady 3rd/4th/5th normal forms zawsze mnie mylą, gdy czytam formalne opisy. Jedna z nich (3rd/4th/5th) zajmuje się polami w zależności od klucza podstawowego i tylko klucza podstawowego. Reguła zakłada, że klucz podstawowy został poprawnie zidentyfikowany (błędnie zdefiniowany klucz podstawowy jest zbyt łatwy do zrobienia).

 -3
Author: user53794,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-16 21:19:13