sql >> Databasteknik >  >> RDS >> Mysql

Vad är sättet att designa en enkel relationsdatabas för lärare-ämne-student-batch?

Du saknar en tabell som associerar ämnen och elever (per punkt 2):

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

Lägg märke till att varje bastabell har en tillhörande uttalandemall för uttalanden om affärssituationen, parametriserad av kolumnnamn - dess (karakteristiska) predikat . Raderna som gör predikatet sant går i tabellen. Lägg märke till att tabelldefinitionen ser ut som en stenografi för predikatet.

// 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]

Eftersom du verkar förvirrad över detta kommer jag att härleda det i termer av hur vi kan resonera för tabell-, begränsnings- och frågedesign. Ett sätt att uttrycka den begränsning du vill ha verkar vara den kommenterade CHECK ovan.

För att uttrycka någon tabell, begränsning eller fråga i SQL bestämmer vi först dess predikat. Sedan kan vi konvertera predikatet till stenografi. Sedan kan vi konvertera stenografin till SQL.

Predikat:

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

Använda bastabellpredikat:

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

Använda stenografier:

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)

I ett FROM representerar varje (möjligen implicit) alias en tabell som det givna bastabellnamnet och/eller underfrågan men med varje kolumn i sitt värde och predikat bytt namn till alias .kolumn .

Vi får raderna som uppfyller OCH för två predikat genom att JOINA predikatens tabeller i SQL. Om vi ​​vill ha rader som uppfyller OCH i ett villkor använder vi ON eller WHERE i SQL.

En SELECT-sats returnerar rader där FÖR VISSA värden för prickade kolumner de returnerade (oprickade) kolumnerna är lika med funktioner i prickade kolumner som uppfyller FROM-predikatet.

SQL:Ersätt satser med deras tabeller, OCH med JOIN eller ON eller WHERE, och yttre FOR SOME &THERE EXISTS med 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

Tabellen med rader som uppfyller ELLER för två predikat är UNION för deras tabeller. För OCH INTE använder vi EXCEPT (aka MINUS) (eller ett LEFT JOIN-formspråk). FÖR NÅGRA eller DET FINNS över alla kolumner går det inte att fråga i SQL, men om vi vill veta om det finns rader som uppfyller ett predikat kan vi använda EXISTS runt en underfråga med det predikatet.

Anta att vi vill begränsa en bastabell så att varje rad uppfyller ett predikat på vissa kolumner. Dvs FÖR ALLA kolumner OM de uppfyller baspredikatet DÅ uppfyller de frågepredikatet. Dvs FÖR ALLA kolumner OM raden de bildar är i basen DÅ finns den i frågan. Så vi kräver i SQL som INTE FINNS (VÄLJ kolumner FRÅN bas UTOM fråga). Eller för varje rad i basen vi kräver i SQL som FINNS(query).

I Standard SQL kan du CREATE ASSERTION CHECK(INTE FINNS (SELECT student_id, batch_id FROM student-batch EXCEPT query)) eller i en CREATE TABLE student-batch kan du CHECK(EXISTS(query)). Tyvärr stöds dessa inte av MySQL eller de flesta DBMS. Om du INSERT till student-batch efter batch kan du kräva att på triggern att EXISTS(query). Eller så kan du lägga till vissa kolumner och sammansatta FK-begränsningar (främmande nyckel).

Nu skriver vi en fråga. Vi vill ha rader där:

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)

Detta ser ut som begränsningspredikatet med olika returkolumner och tillagda rader. SQL är lika direkt översatt. Vi lägger till en koppling med elev för att få studentnamn. Vi lägger till en join med student-batch eftersom begränsningen inte hanterar det; kontexterna som använder begränsningsfrågan kontrollerar om student-batch (student_id, batch_id) underrader finns i den.

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

Du kan prova en PÅ-version:

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



  1. Att lägga till mysql_real_escape_string() gör att tomma värden lagras i databasen

  2. Mysql lagrad procedur ger okänt kolumnfel när den körs

  3. Använda stora parametrar för Microsoft SQL lagrad procedur med DAO

  4. Hur man lägger till en främmande nyckelbegränsning till en befintlig tabell i SQL Server (T-SQL)