Podobne pytanie znajduje się tutaj używanie nadtypu Media i dodawanie podtypów CD, VCR, DVD itp.
Jest to skalowalne, ponieważ tworząc, powiedzmy, podtyp BluRay, tworzysz tabelę zawierającą dane specyficzne dla BluRay i dodajesz wpis do tabeli MediaTypes. Żadne zmiany nie są potrzebne w przypadku istniejących danych lub kodu — z wyjątkiem oczywiście dodania kodu, który będzie działał z danymi BluRay.
W twoim przypadku użytkownicy byliby tabelą nadtypów, a nauczyciele i uczniowie tabelami podtypów.
create table Users(
ID int not null auto_generating,
Type char( 1 ) check( Type in( 'T', 'S' )),
-- other data common to all users,
constraint PK_Users primary key( ID ),
constraint UQ_UserType unique( ID, Type ),
constraint FK_UserTypes foreign key( Type )
references UserTypes( ID )
);
create table Teachers(
TeacherID int not null,
TeacherType char( 1 ) check( TeacherType = 'T' )),
-- other data common to all teachers...,
constraint PK_Teachers primary key( TeacherID ),
constraint FK_TeacherUser foreign key( TeacherID, TeacherType )
references Users( ID, Types )
);
Układ stołu Uczniowie byłby podobny do stołu Nauczyciele.
Ponieważ zarówno nauczyciele, jak i uczniowie mogą zatrudniać innych nauczycieli i uczniów, tabela zawierająca tę relację będzie odnosić się do tabeli Użytkownicy.
create table Employment(
EmployerID int not null,
EmployeeID int not null,
-- other data concerning the employment...,
constraint CK_EmploymentDupes check( EmployerID <> EmployeeID ),
constraint PK_Employment primary key( EmployerID, EmployeeID ),
constraint FK_EmploymentEmployer foreign key( EmployerID )
references Users( ID ),
constraint FK_EmploymentEmployee foreign key( EmployeeID )
references Users( ID )
);
Jak rozumiem, Powiadomienia są pogrupowane według pracodawców:
create table Notifications(
EmployerID int not null
NotificationDate date,
NotificationData varchar( 500 ),
-- other notification data...,
constraint FK_NotificationsEmployer foreign key( EmployerID )
references Users( ID )
);
Zapytania powinny być wystarczająco proste. Na przykład, jeśli użytkownik chciałby zobaczyć wszystkie powiadomienia od swoich pracodawców:
select e.EmployerID, n.NotificationDate, n.NotificationData
from Employment e
join Notifications n
on n.EmployerID = e.EmployerID
where e.EmployeeID = :UserID;
To oczywiście wstępny szkic. Udoskonalenia są możliwe. Ale do twoich ponumerowanych punktów:
- Tabela Zatrudnienie odnosi pracodawców do pracowników. Jedyne sprawdzenie, czy aby zmusić użytkownika, pracodawcy nie mogą sami być pracownikami, ale w przeciwnym razie każdy użytkownik może być zarówno pracownikiem, jak i pracodawcą.
- Tabela Użytkownicy wymusza, aby każdy użytkownik był nauczycielem („T”) lub uczniem („S”). Tylko użytkownicy zdefiniowani jako „T” mogą być umieszczani w tabeli Nauczyciele, a tylko użytkownicy zdefiniowani jako „S” mogą być umieszczani w tabeli Uczniowie.
- Tabela Zatrudnienie łączy się tylko z tabelą Użytkownicy, a nie z tabelami Nauczyciele i Uczniowie. Ale dzieje się tak dlatego, że zarówno nauczyciele, jak i uczniowie mogą być zarówno pracodawcami, jak i pracownikami, nie z powodu wydajności. Ogólnie rzecz biorąc, nie martw się o wydajność podczas początkowego projektowania. Twoim głównym zmartwieniem w tym momencie jest integralność danych. Relacyjne bazy danych są bardzo dobre w przypadku złączeń. Jeśli powinien pojawić się problem z wydajnością, a następnie go naprawić. Nie zmieniaj struktury swoich danych, aby rozwiązać problemy, które jeszcze nie istnieją i mogą nigdy nie istnieć.
- Spróbuj tego i zobacz, jak to działa.