Lieber Rolf,
Die Query wird dadurch verkompliziert, dass die DB hoch normalisiert zu sein scheint.
ja, die Normalisierung habe ich so hoch umgesetzt, wie es mir möglich war.
Das ist nicht immer gut. Eine Query über 9 Tabellen ist schon heftig.
Das mag sein, dafür sind die Datenmengen aber überschaubar.
Beispiel: Welche Users gibt es, außer Staff?
Momentan keine. Der eine Sonderfall läuft über Staff.
Was sind die Extra-Attribute in Staff?
Das, was people
zu staff
macht. Du hast sicher gleich verstanden, dass hier die Mitglieder einer Schulgemeinschaft abgebildet werden. Wir haben Schülerinnen und Schüler (SuS), Kolleginnen und Kollegen (KuK), Eltern und weitere Mitarbeiter. Und da ergibt es sich nun mal, dass manche Menschen mehrere Dinge auf einmal sind, wie z.B. Lehrkräfte, die auch Eltern von SuS an unserer Schule sind. Daher gibt es auch parents
und guardians
, um Elternschaft von Sorgeberechtigung getrennt zu verwalten, und eben auch students
.
Wenn es nur wenige Attribute sind, lohnt es sich, Staff in Users zu integrieren und ein Attribut user_type einzuführen. Das ist dann nicht Normalform, aber performanter.
Darüber könnte man echt nachdenken, aber vielleicht wächst das Projekt irgendwann in eine Richtung, in der auch Eltern oder gar SuS zu Usern werden können. Da will ich das Datenmodell nicht schon wieder anfassen müssen.
Denormalisierung ist oft die Schmiere im DB Getriebe.
So wahr mir Codd helfe.
Eine noch normalisierte DB braucht viel Cache, damit die Joins nicht in die Knie gehen. Ähnliches gilt für students und people. Welche Leute gibt es noch, außer Schülern? Besteht eine Relation zwischen people und users? Kann es sinnvoll sein, auch hier zusammen zu legen? Ok, es mag zu spät dafür sein, weil zuviel Legacy Code da ist.
Wie oben schon beschrieben, stehen zunächst alle Mitglieder der Schulgemeinschaft (lies: alle Menschen) in der Tabelle people
. Die Beziehungen mit anderen Tabellen stellen dann dar, welche Rolle eine Person an der Schule spielt.
Was den Legacy-Code angeht, so ist das mein Projekt, das ich eh immer wieder kräftig umkremple, wenn das Datenmodell so nicht passt, damit eben so etwas wie eine Abhängigkeit von Legacy-Code nicht gegeben ist. Wenn ich falsche Design-Entscheidungen getroffen haben sollte, dann muss ich die korrigieren und nicht das Argument des Legacy-Codes anführen! Dafür ist das Projekt auch gottseidank überschaubar genug.
Es scheint auch einen Modellfehler zu geben. students.form
ist ein Attribut, das nicht nur vom Schüler abhängt, sondern auch vom Datum.
Das ist nicht der Fall. Aber es gibt SuS, die im Verlauf des Schuljahres abgemeldet werden, weil sie die Schule wechseln. Diese müssen in bestimmten Kontexten herausgefiltert werden.
Außerdem gibt es anlassbezogen immer wieder neue Stundenplanversionen im Schuljahr, die neue Kursbildungen notwendig machen können. Daher sind die Kurse mit einem Stundenplan verknüpft, der ein Start-Datum hat.
Oder ist das nur der Zug, in dem der Schüler ist? Aber auch der mag sich ändern; es mag Gründe geben warum ein Schüler von der 5a in die 6b wechselt (z.B. je nach Wahl der 2. Fremdsprache, oder weil die a ihn mobbt). D.h. die Angabe der Klasse (form) gehört an die Kursbuchung. Schüler Willi bucht 2019/20 den Kurs Latein-3 und gehört dann der 8c an.
Eine Klasse ist eine Klasse. Ein Kurs ist ein Kurs. Das eine hat mit dem anderen rein datentechnisch nichts zu tun.
Der Mathe-Unterricht in der 6c ist ein Kurs. Die 6c ist eine Klasse. Die Teilnehmergruppe des Mathe-Kurses ist identisch mit der Klassenliste der 6c. Das gilt auch für das Fach Deutsch, aber nicht unbedingt in allen anderen Fächern. Daher unterscheide ich grundsätzlich zwischen "Klasse" (administrative Kategorie) und "Kurs" (Unterrichtsgruppe mit Fach).
Ist form ein Attribut des Schülers, bekommst Du Probleme beim Abruf von Daten des Vorjahres.
Nein. Die Vorjahre sind archivierte Vorversionen des Projekts, die ihren damaligen Funktionsumfang und ihre damaligen Daten haben.
Willi ist mittlerweile in der 9c, aber wenn Du Kurse vom letzten Schuljahr abfragst, war er noch in der 8c. Du kannst auch nicht einfach 1 abziehen, weil Willi ja nicht in der 9c sein muss. Er kann auch sitzen geblieben oder gesprungen sein.
Dafür müsste ich im Archiv das jeweilige Projekt öffnen.
Was soll die Query eigentlich liefern?
Sie soll alle gebuchten SuS eines bestimmten Nachschreibetermins ermitteln. Dazu muss ich wissen, in welchem Kurs (also Fach und unterrichtende Lehrkräfte) eine versäumte Klassenarbeit nachgeschrieben werden soll. Damit der Kurs einen vernünftigen Bezeichner bekommt, möchte ich nicht nur den Namen des Fachs, sondern auch die betroffenen Klassen ermitteln, sowie die tatsächlichen Unterrichtsstunden (lessons) wegen der zugeordneten KuK, damit da z.B. 7acd Rev Xyz/Abc stehen kann (lies: evangelische Religionslehre unterrichtet von Xyz und Abc).
Prüfungen ab dem 22.9.19 und die zugehörigen Schüler, und zwar für Kurse, wo ein Lehrer mit leerem user-login existiert. Für den geprüften Kurs noch das letzte Subject vor dem Prüfungsdatum - hä?
Die Nachschreibetermine sind über das gesamte Schuljahr verteilt. Wie schon beschrieben ist mit veränderten Stundenplänen und daher anders zusammengesetzten Kursen zu rechnen. Deshalb muss ich für das spezielle Datum des Nachschreibetermins die dafür aktuell geltenden Kurse ermitteln, um für die betroffenen KuK und SuS die richtigen Bezeichner definieren zu können.
Der leere User hätte auch irgend einen Dummy-Wert haben können. Der Admin-Zugang ist keiner Lehrkraft zugeordnet und hat selbst deswegen keinen eigenen Unterricht. Er hat aber übergeordnete Rechte und darf daher bei allen Unterrichten lesen und buchen.
Wofür steht eine Row in einem Kurs, und was für ein Datum ist schedule?
Das Datum bezeichnet den Starttag, ab dem der Stundenplan (schedule) gilt. Neuere Stundenpläne ersetzen ältere.
Eine Row enthält alle notwendigen Daten für einen Kurs, der für diesen Nachschreibetermin gilt.
Was ist das subject eines Kurses? Deutsch? Oder "Gedichtinterpretation" - das hätte ich aber eher an der Lesson vermutet.
Das subject ist das Fach, das im Zeugnis wieder erscheint und dem dort eine Schulnote zugeordnet ist. Also ja, so etwas wie "Deutsch". Das Thema der nachzuschreibenden Arbeit wird in den Kursdaten nicht festgehalten, auch nicht in den Buchungsdaten. Daher ist "Gedichtinterpretation" ein Unterrichtsinhalt, der in den Daten hier nicht vorkommen kann.
In der Tabelle lessons
steht, welcher Kurs zu welchem Zeitpunkt in welchen Räumen bei welchen Lehrkräften Unterricht hat. Dadurch ermittle ich, welche Lehrkräfte für die gebuchte Nachschreibearbeit infrage kommen.
Ich bin auch nicht sicher, dass Du den DISTINCT bei dieser Subquery brauchst, du suchst doch den Kurseintrag mit dem höchsten Schedule-Wert vor der Prüfung, und da gibt's doch vermutlich nur einen, oder? Ich hab ja keine Ahnung was Du in courses genau drin hast 😉
Viele Kursbezeichnungen bleiben über die Stundenplanversionen hin konstant. Suchte ich also nach der Kursbezeichnung, würde die Query mehrere Treffer finden. Ich überlege gerade, inwiefern Dein Einwand vielleicht meine Buchungsdaten dahingehend verändern sollte, dass ich den relevanten Stundenplan für die Buchung mit speichere und nicht schlicht darauf vertraue, dass der jeweils neueste am Tag des Nachschreibetermins gilt. Manchmal sind KuK dazu gezwungen, Nachschreibearbeiten weit in die Zukunft zu buchen, da vorher keine geeigneten Termine sind. Bis dahin kann sich der Stundenplan aber wieder geändert haben.
Danke für diesen Denkanstoß!
Das sieht nach einem SEHR ungewöhnlichen fachlichen Szenario aus. Wenn Du hier Hilfestellung bei einer besseren Query willst, müsstest Du etwas mehr davon erzählen. Das mag dann aber zu viel über eure Schulinterna enthalten.
Ich kann die Funktionalität erläutern. Kein Problem. Das ist weder etwas geheimes, noch intimes. Nur echte Daten darf ich natürlich nicht preisgeben.
Es sieht jedenfalls danach aus, als ob die Lehrer ohne Login der Kern der Sache sind.
Das ist ein Missverständnis. Der Admin-Zugang hat Zugriff auf die kompletten Listen. Da entsteht der Performance-Verlust. Bei jeder anderen Lehrkraft ist die Ergebnismenge wesentlich kleiner (erfahrungsgemäß 0-7), so dass man dort kein Performance-Problem hat. Dort steht dann auch nicht AND 1=1
sondern AND 1=0
, was einen gültigen Loginnamen zwingend notwenig macht, wenn da Ergebnisse kommen sollen.
Oder gehört da eigentlich eine konkrete Login-ID hin und du hast sie weganonymisiert?
Ja, so in etwa.
Liebe Grüße
Felix Riesterer