Mehrstufige abhängige Auswahl
Vor einiger Zeit stand ich bei einem Programm für die Vereinsmeisterschaft unseres Schützenvereines vor der Aufgabe, die Ergebnisanzeige endlich korrekt zu realisieren. Man sollte folgendes auswählen können:
- die Disziplingruppe, also alle Disziplingruppen, Pistole, Gewehr, Flinte, Armbrust etc.
- von der Disziplingruppe abhängend die entsprechende Disziplin, also alle Disziplinen, oder einzelne Disziplinen.
- die Altersklasse, also alle Klassen, Schüler, Jugend, Junioren, Herren, Damen oder abhängig von der Disziplin Auflageschießen sollen dann Seniorenklassen angezeigt werden. Das ist eine spzielle Eigenart im Deutschen Schützenbund.
Irgendwie dachte ich da spontan an das Portal unseres Landesverbandes, der in der Ergebnisliste genau diese Auswahlmöglichkeit (neben der Vereins- und Schützenauswahl) abbildet. Von da aus war der Schritt, wie konkret die Ergebnisse dargestellt werden sollen, nicht weit, nämlich genau so wie im Webportal.
Also mittels dem Untersuchungs-Werkzeug des Firefox Webbrowsers die Struktur der Darstellung analysiert, teils kopiert teils ergänzt/abgewandelt. Als Ergebnis stand am Schluss eine Prozedur die per Buttonklick aufgerufen wird, welche im ersten Teil in Abhängigkeit der Auswahlen einen SQL-String aufbaut. Eine kleine Schwierigkeit dabei war es die Auswahlen für „Alle …“ zu realisieren.
Gelöst habe ich dies indem ich einen String (strCase) zusammengesetzt habe jeweils aus 1 oder 0 für jede Auswahlmöglichkeit. Also „111“ für den Fall dass alle 3 Auswahlen auf „Alle“ stehen bzw. „000“ falls keine oder eben die Zwischenschritte. Danach habe ich die möglichen Fälle bestimmt die jeweils eine andere Zusammensetzung des SQL-Strings bedingen würden und in einer Select Case Schleife abgearbeitet. Das Ergebnis ist relativ komplex, aber ich denke zumindest die Systematik dahinter kann man relativ einfach verstehen:
Select Case strCase Case "111" strSQL = "SELECT tabStarts.*, tabDisziplin.DisziplinNr, tabDisziplin.DisziplinName, tabAltersklassen.Klasse, tabmitglieder.fname, tabmitglieder.vname, tabmitglieder.geboren From ((tabDisziplin INNER JOIN tabStarts ON tabDisziplin.ID = tabStarts.DisziplinID) INNER JOIN tabAltersklassen ON tabStarts.Altersklasse = tabAltersklassen.KlassenNummer) INNER JOIN tabmitglieder ON tabStarts.msbnr = tabmitglieder.msbnr" Case "110" strSQL = "SELECT tabStarts.*, tabDisziplin.DisziplinNr, tabDisziplin.DisziplinName, tabAltersklassen.Klasse, tabmitglieder.fname, tabmitglieder.vname, tabmitglieder.geboren From ((tabDisziplin INNER JOIN tabStarts ON tabDisziplin.ID = tabStarts.DisziplinID) INNER JOIN tabAltersklassen ON tabStarts.Altersklasse = tabAltersklassen.KlassenNummer) INNER JOIN tabmitglieder ON tabStarts.msbnr = tabmitglieder.msbnr Where Altersklasse = " & Me.Altersklasse.Column(1) Case "101", "001" strSQL = "SELECT tabStarts.*, tabDisziplin.DisziplinNr, tabDisziplin.DisziplinName, tabAltersklassen.Klasse, tabmitglieder.fname, tabmitglieder.vname, tabmitglieder.geboren From ((tabDisziplin INNER JOIN tabStarts ON tabDisziplin.ID = tabStarts.DisziplinID) INNER JOIN tabAltersklassen ON tabStarts.Altersklasse = tabAltersklassen.KlassenNummer) INNER JOIN tabmitglieder ON tabStarts.msbnr = tabmitglieder.msbnr Where DisziplinID = """ & Me.Disziplin.Column(1) & """" Case "100", "000" strSQL = "SELECT tabStarts.*, tabDisziplin.DisziplinNr, tabDisziplin.DisziplinName, tabAltersklassen.Klasse, tabmitglieder.fname, tabmitglieder.vname, tabmitglieder.geboren From ((tabDisziplin INNER JOIN tabStarts ON tabDisziplin.ID = tabStarts.DisziplinID) INNER JOIN tabAltersklassen ON tabStarts.Altersklasse = tabAltersklassen.KlassenNummer) INNER JOIN tabmitglieder ON tabStarts.msbnr = tabmitglieder.msbnr Where DisziplinID = """ & Me.Disziplin.Column(1) & """ And Altersklasse = " & Me.Altersklasse.Column(1) Case "011" strSQL = "SELECT tabStarts.*, tabDisziplin.DisziplinNr, tabDisziplin.DisziplinName, tabAltersklassen.Klasse, tabmitglieder.fname, tabmitglieder.vname, tabmitglieder.geboren " & _ "FROM (((tabDisziplin INNER JOIN tabDisziplingruppe ON tabDisziplin.GruppenNr = tabDisziplingruppe.GruppenNr) " & _ "INNER JOIN tabStarts ON tabDisziplin.ID = tabStarts.DisziplinID) " & _ "INNER JOIN tabAltersklassen ON tabStarts.Altersklasse = tabAltersklassen.KlassenNummer) " & _ "INNER JOIN tabmitglieder ON tabStarts.msbnr = tabmitglieder.msbnr " & _ "WHERE tabDisziplin.GruppenNr=" & Me.Disziplingruppe.Column(1) Case "010" strSQL = "SELECT tabStarts.*, tabDisziplin.DisziplinNr, tabDisziplin.DisziplinName, tabAltersklassen.Klasse, tabmitglieder.fname, tabmitglieder.vname, tabmitglieder.geboren " & _ "FROM (((tabDisziplin INNER JOIN tabDisziplingruppe ON tabDisziplin.GruppenNr = tabDisziplingruppe.GruppenNr) " & _ "INNER JOIN tabStarts ON tabDisziplin.ID = tabStarts.DisziplinID) " & _ "INNER JOIN tabAltersklassen ON tabStarts.Altersklasse = tabAltersklassen.KlassenNummer) " & _ "INNER JOIN tabmitglieder ON tabStarts.msbnr = tabmitglieder.msbnr " & _ "WHERE tabDisziplin.GruppenNr=" & Me.Disziplingruppe.Column(1) & " And tabStarts.Altersklasse = " & Me.Altersklasse.Column(1) End Select
Anschließend wird noch die Where-Klausel ergänzt um jeweils nur Daten des ausgewählten Sportjahres (in einer Property definiert) angezeigt zu bekommen, ergänzt um die korrekte Sortierreihenfolge Disziplin, Altersklasse, Ergebnis absteigend:
If InStr(1, strSQL, "Where") = 0 Then strSQL = strSQL & " Where sportjahr = " & pSportjahr Else strSQL = strSQL & " And sportjahr = " & pSportjahr End If strSQL = strSQL & " Order by DisziplinID, Altersklasse, Ergebnis Desc"
Der Code ist sicherlich alles andere als Optimal, aber er funktioniert störungsfrei und das genügt mir.
Im zweiten Teil der Prozedur wird eine HTML-Datei (normale Textdatei mit Endung .html) erstellt, mitBereich mit der Verlinkung auf eine Style-Datei, Tabellenstruktur, Spalten, Spaltenköpfe etc. Die eigentlichen Daten werden in einer Schleife abgearbeitet und geschrieben. Den ganzen Code hier darzustellen würde den Rahmen des Blogs etwas überdehnen, aber im Prinzip funktioniert das wie folgt:
Open CurrentProject.Path & "\index.html" For Output As #1 Print #1, "" Do While Not rs.EOF If strHeadline <> rs!DisziplinNr & "." & rs!Altersklasse & " - " & rs!DisziplinName & " - " & rs!klasse Then If strHeadline <> "" Then Print #1, "</tbody></table>" 'Close Table Print #1, "<div><table class=""meisterTabelle""><tbody><tr><td>" & rs!DisziplinNr & "." & rs!Altersklasse & " - " & rs!DisziplinName & " - " & rs!klasse & "</td></tr></tbody></table></div>" isNewLine = False Else Print #1, "<div><table class=""meisterTabelle""><tbody><tr><td>" & rs!DisziplinNr & "." & rs!Altersklasse & " - " & rs!DisziplinName & " - " & rs!klasse & "</td></tr></tbody></table></div><table class=""ergTabelle"">" isNewLine = True End If Platz = 1 End If strPlatzLine = "<tr><td>" & Platz & "</td><td>" & rs!fname & " " & rs!vname & "</td><td>" & Right(rs!geboren, 4) & "</td><td align=""right""></td><td align=""right""></td><td align=""right""></td><td align=""right""></td><td align=""right""></td><td align=""right""></td><td align=""right"">" & rs!Ergebnis & "</td></tr>" strHeadline = rs!DisziplinNr & "." & rs!Altersklasse & " - " & rs!DisziplinName & " - " & rs!klasse if Platz = 1 And not isNewLine then Print #1, "<table class=""ergTabelle""><tbody>" Print #1, strLine1 & strPlatzLine ElseIf Platz = 1 And isNewLine Then Print #1, strLine1 & strPlatzLine Else Print #1, strPlatzLine End if .... rs.MoveNext loop Close #1
Eine Schwierigkeit hier war es in der Ergebnistabelle die Gruppierungsebenen korrekt darzustellen.
Die Darstellung der Ergebnistabelle erfolgte in einem Unterformular das genau 1 Steuerelement enthält, nämlich ein Microsoft Web Browser Control der Klasse Shell.Explorer.2
Angesteuert wird das Webbrowser-Control direkt nach dem Close-Befehl mit der Navigate Methode:
Me.Parent.Ufo2.Controls(0).Navigate CurrentProject.Path & "\index.html"
Ein Bild wie die Tabelle aussehen könnte möchte ich euch auch nicht vorenthalten, denkt daran es sind alles nur Beispielwerte, lediglich mein Name ist korrekt:
Vorgesehen für die nähere Zukunft ist die Ergebniseingabe in 10er Gruppen, dann muss auch der SQL-String geändert werden, denn dann wird bei Ergebnisgleichheit die letzte Zehnerserie ausgewertet. Auch nochmal eine Eigenheit des Deutschen Schützenbundes.
Ich denke ich hab euch einen kleinen Einblick in mein aktuelles Projekt geben können, und ich denke ihr könnt dies für eure Sportart entsprechend adaptieren wenn gewünscht.
Was ich hier jetzt euch noch unterschlagen habe ist die jeweilige Datenherkunft der Auswahlfelder (Kombinationsfelder). Aber das sollte eigentlich dem ambitionierten Access-Anwender bekannt sein wie man im jeweiligen AfterUpdate-Ereignis der Kombinationsfelder die Datenherkunft des nächsten Auswahlfeldes manipuliert.
Bis dahin
©2024 Andreas Vogt