Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment concevoir une simple base de données relationnelle enseignant-matière-élève-batch ?

Il manque un tableau associant matières et élèves (au point 2) :

// student [student_id] takes subject [subject_id]
takes(student_id, subject_id)

Notez que chaque table de base a un modèle de déclaration associé pour les déclarations sur la situation de l'entreprise, paramétré par des noms de colonne - son prédicat (caractéristique) . Les lignes qui rendent le prédicat vrai vont dans le tableau. Notez que la définition de la table ressemble à un raccourci pour le prédicat.

// teacher [id] named [name] with email [email] teaches subject [subject_id]
teacher(id, name, email, subject_id)

// subject [id] named [name] is [description]
subject(id, name, description)

// student [id] named [name] lives at [location])
student(id, name, location)

// batch [id] at venue [venue] was taught by teacher [teacher_id] on date [date]
batch(id, venue, teacher_id, date)

// student-batch [id] reports student [student_id] being in batch [batch_id]
student-batch(id, student_id, batch_id)
// CHECK student [student_id] takes the subject that is taught by the teacher of batch [batch_id]

Puisque vous semblez perplexe à ce sujet, je vais le dériver en termes de comment nous pouvons raisonner pour la conception de table, de contrainte et de requête. Une façon d'exprimer la contrainte que vous voulez semble être le CHECK commenté ci-dessus.

Pour exprimer une table, une contrainte ou une requête en SQL, nous décidons d'abord de son prédicat. Ensuite, nous pouvons convertir le prédicat en raccourci. Ensuite, nous pouvons convertir le raccourci en SQL.

Prédicat :

student [student_id] takes the subject that is taught by the teacher of batch [batch_id]

Utilisation des prédicats de table de base :

FOR SOME k.*, t.*, b.* (
    student_id = k.student_id AND batch_id = b.bid
AND student [k.student_id] takes subject [k.subject_id]
AND teacher [t.id] named [t.name] with email [t.email] teaches subject [t.subject_id] 
AND batch [b.id] at venue [b.venue] was taught by teacher [b.teacher_id] on date [b.date]
AND [k.subject_id] = [t.subject_id]
AND [t.id] = [b.teacher_id])

Utilisation de raccourcis :

FOR SOME k.*, t.*, b.* (
    student_id = k.student_id AND batch_id = b.bid
AND takes(k.student_id, k.subject_id)
AND teacher(t.id, t.name, t.email, t.subject_id)
AND batch(b.id, b.venue, b.teacher_id, date)
AND k.subject_id = t.subject_id
AND t.id = b.teacher_id)

Dans un FROM, chaque alias (éventuellement implicite) représente une table comme le nom de table de base donné et/ou la sous-requête, mais avec chaque colonne dans sa valeur et son prédicat renommé en alias .colonne .

Nous obtenons les lignes satisfaisant le AND de deux prédicats en JOINANT les tables des prédicats en SQL. Si nous voulons des lignes satisfaisant le AND d'une condition, nous utilisons ON ou WHERE en SQL.

Une clause SELECT renvoie des lignes où POUR CERTAINES valeurs de colonnes en pointillés, les colonnes renvoyées (non pointillées) sont égales aux fonctions de colonnes en pointillés qui satisfont le prédicat FROM.

SQL :Remplacez les instructions par leurs tables, AND par JOIN ou ON ou WHERE, et outer FOR SOME &THERE EXISTS par SELECT :

SELECT t.student_id AS student_id, b.bid AS batch_id
FROM takes k JOIN teacher t JOIN batch b
WHERE k.subject_id = t.subject_id
AND t.id = b.teacher_id
AND student_id = t.student_id
AND batch_id = b.id

La table des lignes satisfaisant le OU de deux prédicats est l'UNION de leurs tables. Pour AND NOT, nous utilisons EXCEPT (alias MINUS) (ou un idiome LEFT JOIN). FOR SOME ou THERE EXISTS sur toutes les colonnes ne peuvent pas être interrogés en SQL, mais si nous voulons savoir s'il existe des lignes satisfaisant un prédicat, nous pouvons utiliser EXISTS autour d'une sous-requête avec ce prédicat.

Supposons que nous voulions contraindre une table de base afin que chaque ligne satisfasse un prédicat sur certaines colonnes. C'est-à-dire POUR TOUTES les colonnes SI elles satisfont le prédicat de base ALORS elles satisfont le prédicat de requête. C'est-à-dire POUR TOUTES les colonnes SI la ligne qu'elles forment est dans la base ALORS elle est dans la requête. Nous avons donc besoin de SQL qui N'EXISTE PAS (SELECT colonnes FROM base EXCEPT query). Ou pour chaque ligne de la base dont nous avons besoin en SQL, EXISTS(query).

En SQL standard, vous pouvez CREATE ASSERTION CHECK(NOT EXISTS (SELECT student_id, batch_id FROM student-batch EXCEPT query)) ou dans un CREATE TABLE student-batch, vous pouvez CHECK(EXISTS(query)). Malheureusement, ceux-ci ne sont pas pris en charge par MySQL ou la plupart des SGBD. Si vous INSÉREZ dans student-batch après batch, vous pouvez exiger sur le déclencheur EXISTS (requête). Ou vous pouvez ajouter certaines colonnes et contraintes composites FK (clé étrangère).

Nous écrivons maintenant une requête. Nous voulons des lignes où :

FOR k.*, t.*, b.*, s.*, sb.* (
    batch = b.id AND teacher = t.name AND student = s.name
AND takes(k.student_id, k.subject_id)
AND teacher(t.id, t.name, t.email, t.subject_id)
AND batch(b.id, b.venue, b.teacher_id, b.date)
AND student(s.id, s.name, s.location)
AND student-batch(sb.id, sb.student_id, sb.batch_id)
AND k.subject_id = t.subject_id
AND t.id = b.teacher_id
AND s.id = k.student_id
AND sb.student_id = k.student_id
AND sb.batch_id = b.id
AND @date = b.date)

Cela ressemble au prédicat de contrainte avec différentes colonnes de retour et des lignes ajoutées. Le SQL est tout aussi directement traduit. Nous ajoutons une jointure avec l'étudiant pour obtenir les noms des étudiants. Nous ajoutons une jointure avec student-batch car la contrainte ne s'en occupe pas; les contextes utilisant la requête de contrainte vérifient si les sous-lignes student-batch (student_id, batch_id) s'y trouvent.

SELECT b.id AS batch, t.name AS teacher, s.name AS student
FROM takes k JOIN teacher t JOIN batch b JOIN student s JOIN student-batch sb
WHERE ... AND @date = date

Vous pouvez essayer une version ON :

SELECT b.id AS Batch, t.name AS Teacher, s.name AS Student
FROM takes k
JOIN teacher t ON k.subject_id = t.subject_id
JOIN batch b ON t.id = b.teacher_id
JOIN ...
WHERE @date = b.date