私は次のようなものを持っています:
Subjects( SubjectId PK, Name, etc... )
Classes( ClassId PK, SubjectId, DateTime periodBegin, etc... )
Students( StudentId PK, Name, etc... )
StudentAttendance( StudentId PK, ClassId PK )
Subjects
には各科目のレコードがClasses
含まれており、学校の予定表で予定されている各クラスのレコードが含まれています。テーブルには、実際のクラス アセンブリを入力する必要があります。Classes
クラス アセンブリが行われるたびに追加するか、学年の開始時にまとめて追加することができます。このStudents
表は一目瞭然で、StudentAttendance
どの学生が特定のクラスに積極的に出席したかを示しています。
のようなテーブルが悪い設計だとは思わないでください。StudentAttendance
これは、多対多結合テーブルの標準的な例です。結合テーブルに数十億の行があるデータベースを目にすることは珍しくありませんが、2 つのキー値 (おそらく int32 または int64) しか含まれていないため、ディスク上のスペースをあまり使用しません。
特定のクラスに出席しなかった学生を検索するクエリを次に示します。
SELECT
Name
FROM
Students
WHERE
StudentId NOT IN (
SELECT
StudentId
FROM
StudentAttendance
INNER JOIN Classes ON StudentAttendance.ClassId = Classes.ClassId
WHERE
StudentAttendance.ClassId = @classId
)
特定の科目に出席した各学生の出席数を取得するクエリを次に示します。これを ( ) で割るSELECT Count(*) FROM Clases WHERE Classes.SubjectId = @subject
と、各生徒の出席率が得られます。生徒が (故意に、または登録されていないために) どのクラスにも出席しなかった場合、その生徒はリストに表示されません。
SELECT
Students.Name
COUNT(*) As AttendanceCount
FROM
StudentAttendance
INNER JOIN Classes ON Classes.ClassId = StudentAttendance.ClassId
INNER JOIN Students ON Students.StudentId = StudentAttendance.StudentId
GROUP BY
StudentId
WHERE
Classes.SubjectId = @subjectId