Geschieht Ihnen das auch regelmäßig Sie wollen mal eben per Abfrage ein paar Daten filtern, sortieren oder zusammenführen, aber die Abfrage nach dieser Anwendung gleich wieder löschen. Dummerweise vergessen Sie Letzteres und irgendwann ist das Datenbankfenster voller gespeicherter Abfragen. Oder Sie benötigen gleichzeitig die Ergebnisse verschiedener Abfragen, finden die vielen geöffneten Fenster im Access-Hauptfenster aber unübersichtlich. Für beides liefert unser Abfrageverwalter die Lösung: Sie können damit mal eben eine Abfrage erstellen, ohne dass diese dauerhaft im Navigationsbereich verbleibt. Oder Sie zeigen die Ergebnisse mehrerer Abfragen übersichtlich im Registersteuerelement eines einzigen Formulars an.
Damit Sie gleich eine Vorstellung davon bekommen, wie diese Lösung aussehen soll, schauen wir uns das Formular aus Bild 1 an. Hier finden Sie eine ganze Reihe Elemente, zuoberst ein Listenfeld. Dieses zeigt alle mit dem Formular erstellten und gespeicherten Abfragen an. Darunter folgen die Steuerelemente für die Verwaltung der Abfragen:
Bild 1: Benutzeroberfläche des Abfrageverwalters
- Neu: öffnet den Entwurf einer neuen, leeren Abfrage.
- Entwurf: Zeigt den Entwurf der im Listenfeld markierten Abfrage an.
- Anzeigen: öffnet die im Listenfeld ausgewählte Abfrage in der Datenblattansicht.
- Löschen: Entfernt die Abfrage aus dem Listenfeld.
- Zur übersicht hinzufügen: Zeigt das Ergebnis der ausgewählten Abfrage auf einer Registerseite im unteren Bereich des Formulars an.
- Aus übersicht entfernen: Entfernt eine Abfrage aus dem Registersteuerelement und blendet die entsprechende Registerseite aus.
Speicherort der Abfragen
Nun werden Sie sich zu Recht fragen: Wenn die Abfragen schon nicht im Navigationsbereich der Datenbank auftauchen, wo werden diese dann gespeichert Ganz einfach: Wie legen für jede hier hinzugefügte Abfrage einen neuen Datensatz in einer speziell für diesen Zweck vorbereiteten Tabelle an.
Diese Tabelle heißt tblAbfragen und sieht in der Entwurfsansicht wie in Bild 2 aus. Das Feld Abfragebezeichnung soll die Bezeichnung aufnehmen und ist als eindeutiger Index ausgelegt. Auf diese Weise verhindern wir, dass die Tabelle mehrere Abfragen mit der gleichen Bezeichnung aufnimmt. Das Feld AbfrageSQL enthält später den SQL-Ausdruck, den Sie mithilfe der Entwurfsansicht für Abfragen zusammengestelt haben. Das Feld Abfrageeigenschaften nimmt die wichtigsten Eigenschaften der Abfrage auf, die Sie üblicherweise über das Eigenschaftsfenster der Abfrage eingeben – wie etwa in Bild 3 die Beschreibung der Abfrage.
Bild 2: Entwurf der Tabelle zum Speichern der Abfragen
Bild 3: Einstellen von Eigenschaften für die Abfrage
Die meisten der hier angegebenen Eigenschaften landen indes ohnehin in Form entsprechender Schlüsselwörter im SQL-Text der Abfrage – zum Beispiel die Eigenschaft Spitzenwerte als TOP.
Das Feld Uebersichtsposition enthält einen Wert, der Folgendes angibt: Wenn das Feld leer ist, soll diese Abfrage nicht in der übersicht der Abfrageergebnisse im Registersteuerelement erscheinen. Nur wenn dieses Feld einen Zahlenwert enthält, soll dies geschehen. In diesem Fall werden die Abfragen in aufsteigender Reihenfolge entsprechend dem Wert des Feldes dort angezeigt.
Damit können wir uns nun an das Formular zur Verwaltung der Abfragen begeben.
Das Formular frmAbfragen
Das Formular sieht in der Entwurfsansicht wie in Bild 4 aus. Es enthält ein Listenfeld zur Anzeige der in der Tabelle tblAbfragen gespeicherten Abfragen, einige Schaltflächen sowie ein Registersteuerelement mit zehn Registerseiten.
Bild 4: Entwurf des Formulars frmAbfragen
Listenfeld zur Anzeige der Abfragen
Das Listenfeld heißt lstAbfragen und verwendet die Abfrage aus Bild 5 als Datensatzherkunft. Diese liefert das Primärschlüsselfeld AbfrageID und die Bezeichnung der Abfrage aus dem Feld Abfragebezeichnung, nach der die Ergebnisse dieser Abfrage auch sortiert werden. Die Eigenschaft Spaltenanzahl des Listenfeldes erhält den Wert 2, die Eigenschaft Spaltenbreiten den Wert 0cm.
Bild 5: Abfrage, die als Datensatzherkunft des Listenfeldes lstAbfragen dient
Neue Abfrage anlegen
Ein Klick auf die Schaltfläche cmdNeu soll eine neue Abfrage in der Entwurfsansicht öffnen und dem Benutzer die Möglichkeit geben, die gewünschten Tabellen und Felder in den Entwurf zu ziehen. Dieser Teil ist einfach und wird durch die folgende Prozedur realisiert:
Private Sub cmdNeu_Click() Dim db As DAO.Database Dim qdf As DAO.QueryDef Set db = CurrentDb strAktuelleAbfrage = "qryTemp_New" On Error Resume Next db.QueryDefs.Delete strAktuelleAbfrage On Error GoTo 0 Set qdf = db.CreateQueryDef(strAktuelleAbfrage) DoCmd.OpenQuery strAktuelleAbfrage, acViewDesign End Sub
Die Prozedur definiert in strAktuelleAbfrage den temporären Namen der zu erstellenden Abfrage. Die Variable strAktuelleAbfrage ist modulweit deklariert:
Private strAktuelleAbfrage As String
Die Prozedur löscht dann eine eventuell noch vorhandene temporäre Abfrage mit dem Namen qryTemp_New und legt diese mit der Methode CreateQueryDef neu an. Danach öffnet die OpenQuery-Methode des DoCmd-Objekts diese Abfrage in der Entwurfsansicht.
Die auf diese Weise geöffnete Abfrage zeigt gar nicht erst das Tabelle anzeigen-Fenster an, sodass Sie die als Datenquelle zu verwendenden Tabellen oder Abfragen direkt aus dem Navigationsbereich in den Abfrageentwurf ziehen können (s. Bild 6).
Bild 6: Anlegen einer neuen Abfrage in der Entwurfsansicht
Mit dem entsprechenden Kontextmenü-Eintrag können Sie dieses Fenster aber auch nachträglich noch anzeigen.
Was aber geschieht, wenn die Abfrage fertiggestellt ist – wie bekommt das Formular mit, dass es soweit ist und wie wird dann die Abfrage in der Tabelle tblAbfragen gespeichert Dazu nutzen wir das Ereignis Bei Aktivierung des Formulars frmAbfragen. Dieses wird beispielsweise ausgelöst, wenn der Benutzer über die Schaltfläche cmdNeu eine neue Abfrage erstellt hat und diese dann schließt. Das Formular wird dann wieder aktiviert und führt die genannte Ereignisprozedur aus.
Deren Code finden Sie in Listing 1. Die Prozedur prüft zunächst, ob die Variable strAktuelleAbfrage einen Wert enthält. Dies ist beispielsweise der Fall, wenn Sie kurz zuvor die Schaltfläche cmdNeu betätigt haben. Ist dies der Fall, prüft die Prozedur auch noch, ob die Abfrage aktuell noch geöffnet ist. Dazu nutzt sie die Hilfsfunktion IstAbfrageGeoeffnet:
Private Sub Form_Activate() Dim db As DAO.Database, qdf As DAO.QueryDef Dim strAbfrageSQL As String, strAbfragebezeichnung As String, strAbfrageeigenschaften As String Dim lngAbfrageID As Long, strSQL As String If Len(strAktuelleAbfrage) > 0 Then If IstAbfrageGeoeffnet(strAktuelleAbfrage) Then MsgBox "Bitte speichern und schließen Sie die temporäre Abfrage ''" & strAktuelleAbfrage & "''" Exit Sub End If Set db = CurrentDb Set qdf = db.QueryDefs(strAktuelleAbfrage) If CDec(qdf.DateCreated) = CDec(qdf.LastUpdated) Then Exit Sub Else strAbfrageSQL = qdf.SQL strAbfrageeigenschaften = Abfrageeigenschaften(qdf) lngAbfrageID = Nz(DLookup("AbfrageID", "tblAbfragen", "''qryTemp_'' & Abfragebezeichnung = ''" _ & qdf.Name & "''"), 0) If lngAbfrageID = 0 Then If MsgBox("Soeben erstellte Abfrage sichern", vbYesNo) = vbYes Then strAbfragebezeichnung = Mid(qdf.Name, 9) strAbfragebezeichnung = InputBox("Bezeichnung der Abfrage: ", "Abfrage speichern", _ strAbfragebezeichnung) Do While Not IsNull(DLookup("AbfrageID", "tblAbfragen", "Abfragebezeichnung = ''" _ & strAbfragebezeichnung & "''")) strAbfragebezeichnung = InputBox("Unter diesem Namen ist bereits eine Abfrage vorhanden. " _ & "Geben Sie eine neue Bezeichnung ein: ", "Abfrage speichern", strAbfragebezeichnung) Loop If Len(strAbfragebezeichnung) = 0 Then Exit Sub End If If Len(strAbfragebezeichnung) > 0 Then strSQL = "INSERT INTO tblAbfragen(Abfragebezeichnung, AbfrageSQL, Abfrageeigenschaften) " _ & "VALUES(''" & strAbfragebezeichnung & "'', ''" & strAbfrageSQL & "'', ''" _ & Replace(Replace(strAbfrageeigenschaften, """", "''"), "''", "''''") & "'')" db.Execute strSQL, dbFailOnError End If End If Me!lstAbfragen.Requery Else If MsgBox("Soeben geänderte Abfrage speichern", vbYesNo) = vbYes Then strSQL = "UPDATE tblAbfragen SET AbfrageSQL = ''" & strAbfrageSQL & "'', Abfrageeigenschaften = ''" _ & strAbfrageeigenschaften & "'' WHERE AbfrageID = " & lngAbfrageID db.Execute strSQL, dbFailOnError End If End If End If strAktuelleAbfrage = "" End If End Sub
Listing 1: Diese Prozedur prüft, ob der Benutzer neue Abfragen angelegt hat, und speichert gegebenenfalls die Daten.
Private Function IstAbfrageGeoeffnet(strAbfrage As _ String) As Boolean IstAbfrageGeoeffnet = _ SysCmd(acSysCmdGetObjectState, acQuery, strAbfrage) End Function
Ist die Abfrage noch geöffnet, erscheint eine Meldung, die den Benutzer darüber informiert, dass die Abfrage gespeichert und geschlossen werden muss. Die Prozedur wird dann beendet.
Ist die Abfrage nicht mehr geöffnet, referenziert die Prozedur das QueryDef-Objekt zu dieser Abfrage mit der Variablen qdf und vergleicht das Datum der Erstellung mit dem änderungsdatum. Sind die Daten gleich, hat der Benutzer seit der Erstellung keine änderungen vorgenommen und die Abfrage braucht nicht gespeichert zu werden.
Anderenfalls liest die Prozedur den SQL-Code der Abfrage in die Variable strAbfrageSQL ein und die Eigenschaften in die Variable strAbfrageEigenschaften – dazu später mehr. Sie liest dann den Primärschlüsselwert einer eventuell bereits in der Tabelle tblAbfragen gespeicherten Abfrage in die Variable lngAbfrageID ein.
Nur wenn noch keine Abfrage gleichen Namens vorhanden ist, fragt die Prozedur den Benutzer, ob dieser die erstellte Abfrage sichern möchte. Dann fragt die folgende InputBox-Funktion den Namen ab, unter dem die Abfrage gespeichert werden soll. Die folgende Do While-Schleife wird so lange durchlaufen, bis der Benutzer eine Bezeichnung eingegeben hat, die noch nicht in der Tabelle vorhanden ist. Dies kann natürlich schon nach der bereits erfolgten Eingabe in die InputBox der Fall sein. Falls nicht, erscheint eine weitere InputBox und fragt erneut die zu verwendende Bezeichnung ab.
Die Schleife wird erst verlassen, wenn eine noch nicht verwendete Bezeichnung eingegeben wurde – oder gar keine. Dies kann der Benutzer durch eine entsprechende Eingabe erreichen oder aber durch das Anklicken der Abbrechen-Schaltfläche der InputBox.
Diesen Fall prüft die erste If…Then-Bedingung nach der Do While-Schleife und beendet die Prozedur im Falle einer leeren Abfragebezeichnung.
Erst wenn eine gültige Abfragebezeichnung vorliegt, kann es weitergehen. Dann stellt die Prozedur in strSQL eine INSERT INTO-Aktionsabfrage zusammen, welche die ermittelten Daten in einen neuen Datensatz der Tabelle tblAbfragen schreibt, führt diese aus und aktualisiert den Inhalt des Listenfeldes, das nun den neuen Datensatz anzeigen sollte.