Il y a une question similaire ici en utilisant un supertype Media et en ajoutant des sous-types de CD, VCR, DVD, etc.
Ceci est évolutif dans la mesure où lors de la création, par exemple, d'un sous-type BluRay, vous créez la table pour contenir les données spécifiques à BluRay et ajoutez une entrée à la table MediaTypes. Aucune modification n'est nécessaire pour les données ou le code existants, sauf, bien sûr, pour ajouter le code qui fonctionnera avec les données BluRay.
Dans votre cas, Users serait la table de supertype avec Teachers et Students les tables de sous-type.
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 )
);
La composition de la table des étudiants serait similaire à celle de la table des enseignants.
Étant donné que les enseignants et les étudiants peuvent employer d'autres enseignants et étudiants, la table qui contient cette relation ferait référence à la table des utilisateurs.
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 )
);
Si j'ai bien compris, les notifications sont regroupées par employeur :
create table Notifications(
EmployerID int not null
NotificationDate date,
NotificationData varchar( 500 ),
-- other notification data...,
constraint FK_NotificationsEmployer foreign key( EmployerID )
references Users( ID )
);
Les requêtes doivent être suffisamment simples. Par exemple, si un utilisateur souhaite voir toutes les notifications de son/ses employeur(s) :
select e.EmployerID, n.NotificationDate, n.NotificationData
from Employment e
join Notifications n
on n.EmployerID = e.EmployerID
where e.EmployeeID = :UserID;
Ceci est une première esquisse, bien sûr. Des raffinements sont possibles. Mais à vos points numérotés :
- Le tableau Emploi relie les employeurs aux employés. La seule vérification consiste à faire en sorte que les employeurs des utilisateurs ne puissent pas être eux-mêmes des employés, mais sinon, tout utilisateur peut être à la fois un employé et un employeur.
- Le tableau des utilisateurs force chaque utilisateur à être soit un enseignant ('T') soit un étudiant ('S'). Seuls les utilisateurs définis comme 'T' peuvent être placés dans le tableau Enseignants et seuls les utilisateurs définis comme 'S' peuvent être placés dans le tableau Élèves.
- La table Emploi se joint uniquement à la table Utilisateurs, et non aux tables Enseignants et Étudiants. Mais c'est parce que les enseignants et les étudiants peuvent être à la fois employeurs et employés, et non pour une quelconque raison de performance. En général, ne vous souciez pas des performances lors de la conception initiale. Votre principale préoccupation à ce stade est l'intégrité des données. Les bases de données relationnelles sont très bonnes avec les jointures. Si un problème de performances devrait survenir, puis corrigez-le. Ne restructurez pas vos données pour résoudre des problèmes qui n'existent pas encore et qui n'existeront peut-être jamais.
- Eh bien, essayez ceci et voyez comment cela fonctionne.