HTML-Kreuztabelle 3: Neue Zeilen und Spalten

Lies diesen Artikel und viele weitere mit einem kostenlosen, einwöchigen Testzugang.

In den ersten beiden Teilen der Beitragsreihe haben wir gezeigt, wie Sie die Daten einer Tabelle in Form einer Kreuztabelle ausgeben können. Das ist natürlich auch per Kreuztabellenabfrage möglich, aber wir haben in diesem Fall das Webbrowser-Steuerelement mit einer entsprechenden HTML-Seite verwendet. Der Hintergrund ist, dass wir so Funktionen zum direkten Bearbeiten der Einträge hinzufügen können – vorausgesetzt, dass die Kreuztabelle nur die Werte einer Kombination anzeigt und nicht etwa Domänenfunktionen wie Summen oder Mittelwerte. Wir wollen also die bereits vorhandene Darstellung noch um Funktionen zum Bearbeiten sowie zum Hinzufügen neuer Spalten oder Zeilen erweitern.

Ausgangspunkt ist die in den bereits genannten Beiträgen HTML-Kreuztabelle 1: Basics (www.access-im-unternehmen.de/1161) und HTML-Kreuztabelle 2: Werte bearbeiten (www.access-im-unternehmen.de/1162) erarbeitete Lösung. Hier wollen wir nun folgende Erweiterungen hinzufügen:

  • In der oberen Zeile mit den Spaltenköpfen wollen wir rechts ein Plus-Zeichen anzeigen, mit dem der Benutzer eine neue Spalte hinzufügen kann.
  • In der linken Zeile mit den Zeilenköpfen wollen wir unten ebenfalls ein Plus-Zeichen unterbringen, das per Mausklick die Möglichkeit zum Anlegen einer neuen Zeile ermöglicht.
  • Ein Doppelklick auf einen der Werte soll den entsprechenden Datensatz der Tabelle tblMaterialpreise in einem eigenen Formular öffnen.

Neue Zeilen und Spalten anlegen

Für das Anlegen neuer Zeilen und Spalten haben wir uns weiter oben vorgenommen, rechts neben den Spaltenüberschriften und unter den Zeilenüberschriften jeweils ein Plus-Zeichen anzuzeigen, über das wir eine neue Zeile oder Spalte hinzufügen können. Wir könnten dann, wenn der Benutzer auf eines der beiden Plus-Zeichen klickt, einfach die neue Zeile hinzufügen. Aber geht das wirklich so einfach Nein: Denn unser Algorithmus aus der Prozedur KreuztabelleAnlegen fügt nur Spalten und Zeilen an für Höhen- oder Breitenangaben, zu denen es auch bereits mindestens eine Preisangabe gibt. Dementsprechend haben wir auch gar keine Möglichkeit, Daten so in der Tabelle tblMaterialpreise zu speichern, dass diese allein in der Anzeige einer neuen Zeile oder Spalte münden, ohne selbst einen Preis für die Kombination aus Höhe und Breite zu enthalten.

Also müssen wir uns einen alternativen Weg ausdenken, der wie folgt aussieht könnte: Wenn der Benutzer einen Preis für eine Kombination aus Höhe und Breite angeben möchte, von denen entweder die Höhe oder die Breite oder auch beides noch nicht vorhanden ist, muss er eben einen neuen Datensatz in der Tabelle tblMaterialpreise einfügen, der die gewünschten Werte für Höhe und Breite enthält.

Letztlich wäre es aber intuitiver, wenn der Benutzer einfach auf ein Plus-Zeichen zum Erstellen einer neuen Zeile oder Spalte klickt und dann durch einen Klick auf die entstehenden Zellen mit dem Minus-Zeichen den neuen Preis eingibt.

Was aber benötigen wir, um dies zu realisieren Richtig, wir müssten die verfügbaren Werte für die Höhen und Breiten in jeweils einer weiteren Tabelle vorhalten. In der aktuellen Konstellation ist das auch möglich, denn wir gehen ja erstmal von einem einzigen Material aus. In der Praxis ist unser Ansatz aber natürlich zu kurz gedacht – wir werden auch verschiedene Materialien berücksichtigen müssen, die wir in einer weiteren Tabelle speichern, die etwa tblMaterialien heißt. Auf diese Tabelle verweisen wir dann von der Tabelle tblMaterialpreise aus per Fremdschlüsselfeld. Ebenso können wir auf diese Tabelle dann von den beiden Tabellen zum Speichern von Höhen und Breiten verweisen. Also legen wir diese Tabellen an. Auf das Hinzufügen neuer Zeilen und Spalten kommen wir später zurück – vorher sind noch einige Vorbereitungen und Erweiterungen zu erledigen.

Tabelle zum Speichern der Materialien

Die Tabelle tblMaterialien soll die verschiedenen Materialien aufnehmen, damit wir die Materialpreise nicht nur in Abhängigkeit der Kombinationen von Höhe und Breite, sondern auch in Abhängigkeit von verschiedenen Materialien erfassen können, also etwa 17 mm und 19 mm dicke Spanplatten. Die Tabelle enthält zwei Felder: Das Feld MaterialID ist das Primärschlüsselfeld, das Feld Bezeichnung legt den Namen des Materials fest. Für dieses Feld legen wir einen eindeutigen Index fest, damit jede Bezeichnung nur einmal eingegeben werden kann (siehe Bild 1).

Die Tabelle tblMaterialien

Bild 1: Die Tabelle tblMaterialien

Tabellen zum Speichern von Höhen und Breiten

Die Tabelle zum Speichern der Höhen heißt tblHoehen. Sie enthält ein Primärschlüsselfeld namens HoeheID, das Feld Hoehe zum Angeben der Höhe und das Fremdschlüsselfeld MaterialID, über das die Höhe einem Datensatz der Tabelle tblMaterialien zugeordnet wird. Für die beiden Felder Hoehe und MaterialID legen wir einen eindeutigen, zusammengesetzten Schlüssel fest. So verhindern wir, dass für ein Material die gleiche Höhe doppelt angelegt wird (siehe Bild 2).

Die Tabelle tblHoehen

Bild 2: Die Tabelle tblHoehen

Die Tabelle tblBreiten bauen wir analog zur Tabelle tblHoehen auf.

Materialpreis nach Material

Schließlich wollen wir der Tabelle tblMaterialpreise noch ein Fremdschlüsselfeld namens MaterialID hinzufügen, mit dem wir den entsprechenden Eintrag der Tabelle tblMaterialien auswählen. Auch hier müssen wir das neue Feld Material-ID in den eindeutigen Index integrieren. Die neue Version der Tabelle sieht nun wie in Bild 3 aus.

Die angepasste Tabelle tblMaterialpreise

Bild 3: Die angepasste Tabelle tblMaterialpreise

Das Datenmodell enthält nun vier Tabellen, die wie in Bild 4 miteinander verknüpft sind.

Aktueller Stand des Datenmodells

Bild 4: Aktueller Stand des Datenmodells

Material anlegen

Nun fügen wir einige Einträge zur Tabelle tblMaterialien hinzu, zum Beispiel Spanplatte 17 mm und Spanplatte 19 mm. Anschließend verbinden wir alle Datensätze der Tabelle tblMaterialpreise, die wir bisher angelegt haben, über das Feld MaterialID mit dem ersten der beiden neu angelegten Datensätze der Tabelle tblMaterialien. Das Ergebnis sieht in der Tabelle tblMaterialpreise dann etwa wie in Bild 5 aus.

Inhalt der Tabelle tblMaterialpreise

Bild 5: Inhalt der Tabelle tblMaterialpreise

Außerdem fügen wir in den beiden Tabellen tblHoehen und tblBreiten die Werte ein, die bereits in der Tabelle tblMaterialpreise vorliegen.

Höhen und Breiten verknüpfen

An dieser Stelle fragen wir uns auch: Sollten wir nicht die Felder Hoehe und Breite der Tabelle tblMaterialpreise mit den entsprechenden Datensätzen der Tabelle tblHoehen und tblBreiten verknüpfen Und würde es dann nicht sogar Sinn machen, hier einmal auf einen Autowert in den Primärschlüsselfeldern der beiden Tabellen tblHoehen und tblBreiten zu verzichten und direkt die Werte der Höhen und Breiten in das Primärschlüsselfeld einzutragen Dann hätten wir die für uns interessanten Werte direkt in den gebundenen Spalten der Fremdschlüsselfelder und müssten gar keine Lookup-Abfragen tätigen, um auf die Werte der Tabellen tblHoehen und tblBreiten zugreifen – diese würden dann lediglich zur Beschränkung der möglichen Werte dienen, die in den Fremdschlüsselfeldern Hoehe und Breite eingegeben beziehungsweise ausgewählt werden können.

Das erledigen wir schließlich, indem wir die Beziehungen wie in Bild 6 hinzufügen. Vorher haben wir die Primärschlüsselfelder HoeheID und BreiteID aus den Tabellen tblHoehen und tblBreiten entfernt und die Felder Hoehe und Breite in Primärschlüsselfelder ohne Autowert umgewandelt.

Neue Verknüpfungen im Datenmodell

Bild 6: Neue Verknüpfungen im Datenmodell

Werte für neues Material hinzufügen

Damit wir neue Daten zum Spielen haben, fügen wir der Tabelle tblMaterialien einen zweiten Datensatz hinzu (siehe Bild 7).

Neuer Datensatz in der Tabelle tblMaterialien

Bild 7: Neuer Datensatz in der Tabelle tblMaterialien

Außerdem fügen wir in den beiden Tabellen tblHoehen und tblBreiten einige neue Datensätze mit Werten für die neue Materialart ein. Zur Unterscheidung von den Datensätzen für die bereits vorhandene Materialart nutzen wir hier kleinere Werte (100 bis 300) – siehe Bild 8.

Neue Werte für Höhe und Breite für das zuletzt hinzugefügte Material

Bild 8: Neue Werte für Höhe und Breite für das zuletzt hinzugefügte Material

Schließlich legen wir einige neue Datensätze in der Tabelle tblMaterialpreise für das neue Material an (siehe Bild 9).

Materialpreise für neues Material

Bild 9: Materialpreise für neues Material

Wenn wir nun das Formular mit der Kreuztabelle öffnen, sieht dieses wie in Bild 10 aus. Hier werden nun alle Maße und alle Preise angezeigt – sowohl für die 17 mm als auch für die 19 mm dicken Spanplatten. Leider kann man diese aktuell nur dadurch auseinanderhalten, dass wir für die eine Spanplatte die kleineren Höhen und Breiten und für die andere die größeren festgelegt haben.

Kreuztabelle mit neuen Daten

Bild 10: Kreuztabelle mit neuen Daten

Damit nur die Werte für eines der Materialien angezeigt werden, fügen wir dem Formular nun ein Kombinationsfeld hinzu, mit dem der Benutzer das Material auswählen kann. Das neue Kombinationsfeld nennen wir cboMaterial-ID. Für seine Eigenschaft Datensatzherkunft legen wir die folgende Abfrage fest:

SELECT MaterialID, Bezeichnung FROM tblMaterialien 
ORDER BY Bezeichnung;

Damit nur das Feld Bezeichnung im Kombinationsfeld angezeigt wird und nicht das Primärschlüsselfeld Material-ID, stellen wir die Eigenschaft Spaltenanzahl auf 2 und Spaltenbreiten auf 0cm ein.

Nun benötigen wir noch eine Ereignisprozedur, die nach der Auswahl eines neuen Eintrags im Kombinationsfeld die Kreuztabelle neu füllt. Der dazu aufgerufenen Prozedur KreuztabelleErstellen müssen wir auch noch an irgendeiner Stelle die Information mitgeben, für welches Material das Webbrowser-Steuerelement die Preise anzeigen soll.

Die Ereignisprozedur implementieren wir wie folgt:

Private Sub cboMaterialID_AfterUpdate()
     KreuztabelleErstellen Me!cboMaterialID
End Sub

Hier haben wir bereits vorgegriffen, auf welche Art wir das betroffene Material übergeben – nämlich als Parameter der Prozedur KreuztabelleErstellen. Diese erweitern wir um den entsprechenden Parameter. Außerdem fügen wir der Abfrage, welche die anzuzeigenden Daten für die Kreuztabelle in der Prozedur KreuztabelleErstellen ermittelt, ein WHERE-Kriterium mit dem Wert des Parameters hinzu. Das sieht dann gekürzt wie folgt aus:

Private Sub KreuztabelleErstellen(lngMaterialID As Long)
     ...
     Set rstSpaltenkoepfe = db.OpenRecordset( _
          "SELECT  DISTINCT Hoehe FROM tblMaterialpreise  WHERE MaterialID = " _
          & lngMaterialID & "  ORDER BY Hoehe", dbOpenDynaset)
     ...
     Set rstZeilen = db.OpenRecordset( _
          "SELECT DISTINCT  Breite FROM tblMaterialpreise  WHERE MaterialID = " _
          & lngMaterialID & "  ORDER BY Breite", dbOpenDynaset)
     Do While Not rstZeilen.EOF
         ...
         Set rstWerte = db.OpenRecordset( _
               "SELECT  MaterialpreisID, Preis, Hoehe  FROM tblMaterialpreise WHERE MaterialID = "  _
               & lngMaterialID & " AND Breite = " &  rstZeilen!Breite & " ORDER BY Hoehe", dbOpenDynaset)
         ...
     Loop
End Sub

Außerdem müssen wir noch die Prozedur anpassen, die beim öffnen des Formulars das Webbrowser-Steuerelement füllt und dazu die Prozedur KreuztabelleErstellen aufruft:

Private Sub Form_Timer()
     ...
     Me!cboMaterialID = Me!cboMaterialID.ItemData(0)
     KreuztabelleErstellen Me!cboMaterialID
End Sub

Damit sorgen wir nun dafür, dass erstens beim Anzeigen des Formulars, was auch das Ereignis Form_Timer auslöst (siehe erster Teil der Beitragsreihe) der erste Eintrag des Kombinationsfeldes eingestellt wird und zweitens dafür, dass die Prozedur KreuztabelleErstellen mit dem Primärschlüsselwert des gewählten Eintrags aufgerufen wird. Dies führt dann beispielsweise zu einer Ansicht wie in Bild 11.

Preise nur für die gewählte Materialart

Bild 11: Preise nur für die gewählte Materialart

Wenn wir nun mit dem Kombinationsfeld den zweiten Eintrag auswählen, geschieht allerdings etwas Unerwartetes – siehe Bild 12. Die Kreuztabelle für die neu ausgewählte Materialart wird unten angefügt! Dies können wir allerdings leicht ändern. Dazu fügen wir vor der Anweisung, mit der wir das neue Tabellenelement anlegen, einen Befehl ein, der die Eigenschaft innerHTML des body-Elements auf eine leere Zeichenkette einstellt:

Zwei Kreuztabellen untereinander

Bild 12: Zwei Kreuztabellen untereinander

Private Sub KreuztabelleErstellen(lngMaterialID As Long)
     ...
     objDocument.body.innerHTML = ""
     Set objTable = objDocument.createElement("Table")
     ...

Damit können wir dann über das Kombinationsfeld leicht zwischen den Materialarten wechseln.

Prozedur anpassen, damit auch nicht verwendete Werte in der Kreuztabelle erscheinen

Nun folgt ein weiterer wichtiger Schritt: Wir haben ja bereits die Tabellen tblHoehen und tblBreiten angelegt, damit wir auch schon Höhen und Breiten eingeben können, für die der Benutzer vielleicht noch gar keine Preise festgelegt hat. Dementsprechend werden die Höhen und Breiten auch beim Anzeigen der Spalten und Zeilen in der Kreuztabelle noch nicht berücksichtigt – dort berücksichtigen wir nur die Werte, die bereits in der Tabelle tblMaterialpreise enthalten sind.

Das wollen wir aber nun ändern, damit auch die noch nicht mit Preisen versehenen Kombinationen aus Höhe und Breite bereits angezeigt und dann vom Benutzer in der Kreuztabelle bearbeitet werden können.

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

Testzugang

eine Woche kostenlosen Zugriff auf diesen und mehr als 1.000 weitere Artikel

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar