科目と学生を関連付けるテーブルがありません(ポイント2ごと):
// student [student_id] takes subject [subject_id]
takes(student_id, subject_id)
各ベーステーブルには、ビジネス状況に関するステートメントに関連付けられたステートメントテンプレートがあり、列名でパラメーター化されていることに注意してください。その(特性)述語 。述語をtrueにする行がテーブルに表示されます。テーブル定義が述語の省略形のように見えることに注意してください。
// 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]
あなたはこれについて困惑しているように見えるので、テーブル、制約、およびクエリの設計をどのように推論できるかという観点からそれを導き出します。必要な制約を表現する1つの方法は、上記のコメント付きのCHECKのようです。
SQLでテーブル、制約、またはクエリを表現するには、最初にその述語を決定します。次に、述語を省略形に変換できます。次に、省略形をSQLに変換できます。
述語:
student [student_id] takes the subject that is taught by the teacher of batch [batch_id]
ベーステーブル述語の使用:
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])
速記の使用:
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)
FROMでは、各(おそらく暗黙の)エイリアスは、指定されたベーステーブル名やサブクエリのようなテーブルを表しますが、値と述語の各列の名前がエイリアスに変更されます。 。列 。
SQLで述語のテーブルを結合することにより、2つの述語のANDを満たす行を取得します。条件のANDを満たす行が必要な場合は、SQLでONまたはWHEREを使用します。
SELECT句は、点線の列のFOR SOME値が返される(点線のない)列がFROM述語を満たす点線の列の関数と等しい行を返します。
SQL:ステートメントをテーブルに置き換え、JOINまたはONまたはWHEREに置き換え、外部のFOR SOME&THERE EXISTSを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
2つの述部のORを満たす行のテーブルは、それらのテーブルのUNIONです。 AND NOTの場合、EXCEPT(別名MINUS)(またはLEFT JOINイディオム)を使用します。一部またはすべての列の存在をSQLで照会することはできませんが、述語を満たす行があるかどうかを知りたい場合は、その述語を持つサブクエリの周囲にEXISTSを使用できます。
すべての行がいくつかの列の述語を満たすように、ベーステーブルを制約するとします。つまり、すべての列が基本述語を満たしている場合は、クエリ述語を満たしています。つまり、すべての列に対して、それらが形成する行がベースにある場合、それはクエリにあります。したがって、SQLではNOT EXISTS(SELECT列FROMベースEXCEPTクエリ)が必要です。または、ベースの各行に対して、SQLでEXISTS(クエリ)が必要です。
標準SQLでは、CREATE ASSERTION CHECK(NOT EXISTS(SELECT student_id、batch_id FROM student-batch EXCEPT query))またはCREATE TABLE Student-batchではCHECK(EXISTS(query))を実行できます。残念ながら、これらはMySQLまたはほとんどのDBMSではサポートされていません。バッチの後にstudent-batchにINSERTする場合は、トリガー時にEXISTS(query)を要求できます。または、特定の列と複合FK(外部キー)制約を追加することもできます。
今、私たちはクエリを書いています。次のような行が必要です:
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)
これは、異なる戻り列と追加された行を持つ制約述語のように見えます。 SQLも同様に直接変換されます。学生の名前を取得するために、学生との結合を追加します。制約がそれを処理しないため、student-batchを使用して結合を追加します。制約クエリを使用するコンテキストは、student-batch(student_id、batch_id)サブ行がその中にあるかどうかをチェックします。
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
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