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.
Nun folgt noch der Fall, dass die Abfrage bereits gespeichert wurde. Dies geschieht, um etwas vorzugreifen, beispielsweise dann, wenn der Benutzer eine bereits gespeicherte Abfrage im Entwurf öffnet und diese ändert.
In diesem Fall fragt die Prozedur per MsgBox, ob die geänderte Abfrage gespeichert werden soll. Dies erledigt dann eine entsprechende UPDATE-Anweisung.
Schließlich stellt die Prozedur den Wert von strAktuelleAbfrage auf eine leere Zeichenkette ein, damit die Prozedur Form_Activate beim nächsten Aktivieren des Formulars ohne zwischenzeitliches Erstellen oder öffnen einer der gespeicherten Abfragen weiß, dass nichts zu tun ist.
Eigenschaften der Abfrage speichern
Vorhin wurde auch die Funktion Abfrageeigenschaften erwähnt, welche die Eigenschaften einer Abfrage ermitteln soll. Diese finden Sie in Listing 2. Die Funktion erwartet lediglich einen Verweis auf das QueryDef-Objekt dieser Abfrage und liefert eine Zeichenkette zurück, welche die Eigenschaften und ihre Werte etwa wie folgt enthält, also als Name-Wert-Paare, die durch das Pipe-Zeichen (|) voneinander getrennt sind:
Private Function Abfrageeigenschaften(qdf As DAO.QueryDef) As String Dim prp As DAO.Property Dim strEigenschaften As String For Each prp In qdf.Properties Select Case prp.Name Case "StillExecuting", "CacheSize", "Prepare", "DOL", "NameMap", "DateCreated", "LastUpdated", "Type", _ "Updatable", "RecordsAffected", "RecordLocks", "RecordsetType", "Name" Case Else On Error Resume Next strEigenschaften = strEigenschaften & prp.Name & "=" & prp.Value & "|" If Not Err.Number = 0 Then Debug.Print prp.Name, prp.Value End If On Error GoTo 0 End Select Next prp If Len(strEigenschaften) > 0 Then strEigenschaften = Left(strEigenschaften, Len(strEigenschaften) - 1) End If Abfrageeigenschaften = strEigenschaften End Function
Listing 2: Einlesen der Eigenschaften einer Abfrage und ihrer Werte in eine Zeichenkette
SQL=SELECT ...|Connect=|ReturnsRecords=Wahr|ODBCTimeout=60|MaxRecords=0| OrderByOn=Falsch|Orientation=0|DefaultView=2|GUID=|FilterOnLoad=Falsch| OrderByOnLoad=Wahr|TotalsRow=Falsch|FilterOn=Wahr|Description=Beispielbeschreibung|...
Die Funktion durchläuft alle Property-Elemente der Properties-Auflistung und schließt einige Elemente aus, die entweder nicht eingelesen werden können oder keinen Nutzen haben. Dabei stellt sie in der Variablen strEigenschaften eine Zeichenkette wie oben dargestellt zusammen. Diese wird anschließend noch um das zuletzt hinzugefügte Pipe-Zeichen gekürzt und als Funktionswert an die aufrufende Prozedur zurückgegeben. Damit ist der Vorgang zum Speichern der Definition einer Abfrage in der Tabelle tblAbfragen abgeschlossen.
Entwurf einer Abfrage öffnen
Die zweite Schaltfläche des Formulars heißt cmdEntwurf und soll die aktuell im Listenfeld markierte Abfrage in der Entwurfsansicht anzeigen. Dies geschieht primär durch die folgende Ereignisprozedur, die allerdings zwei weitere Routinen aufruft:
Private Sub cmdEntwurf_Click() Dim strAbfrage As String strAbfrage = AbfrageErstellen(Nz(Me!lstAbfragen, 0)) If Not Len(strAbfrage) = 0 Then AbfrageOeffnen strAbfrage, acViewDesign End If End Sub
Die erste heißt AbfrageErstellen und soll basierend auf den in der Tabelle tblAbfragen gespeicherten Daten ein neues QueryDef-Objekt erstellen (s. Listing 3). Dabei soll der Name der erstellten Abfrage als Funktionswert zurückgeliefert werden. Den Namen der frisch erstellten Abfrage übergibt die Prozedur dann an die Routine AbfrageOeffnen, welche die Abfrage in der Entwurfsansicht öffnen soll. Dazu erhält diese Routine außerdem als zweiten Parameter den Wert acViewDesign.
Private Function AbfrageErstellen(lngAbfrageID As Long) As String Dim db As DAO.Database Dim qdf As DAO.QueryDef Dim rst As DAO.Recordset Dim strEigenschaften() As String Dim i As Integer Dim varWert As Variant Dim prp As DAO.Property Dim lngError As Long If lngAbfrageID = 0 Then Exit Function End If Set db = CurrentDb Set rst = db.OpenRecordset("SELECT * FROM tblAbfragen WHERE AbfrageID = " & lngAbfrageID, dbOpenDynaset) strAktuelleAbfrage = "qryTemp_" & rst!Abfragebezeichnung On Error Resume Next db.QueryDefs.Delete strAktuelleAbfrage On Error GoTo 0 Set qdf = db.CreateQueryDef(strAktuelleAbfrage, rst!AbfrageSQL) strEigenschaften = Split(rst!Abfrageeigenschaften, "|") For i = LBound(strEigenschaften) To UBound(strEigenschaften) varWert = Split(strEigenschaften(i), "=")(1) varWert = Replace(varWert, "Wahr", -1) varWert = Replace(varWert, "Falsch", 0) On Error Resume Next qdf.Properties(Split(strEigenschaften(i), "=")(0)) = varWert lngError = Err.Number On Error GoTo 0 If lngError = 3270 Then Set prp = qdf.CreateProperty(Split(strEigenschaften(i))(0)) Select Case strEigenschaften(i) Case Else prp.Type = dbText End Select prp.Value = varWert qdf.Properties.Append prp End If Next i AbfrageErstellen = strAktuelleAbfrage End Function
Listing 3: Erstellen einer Abfrage aus dem in der Tabelle tblAbfragen gespeicherten Daten
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
den kompletten Artikel im PDF-Format mit Beispieldatenbank
diesen und alle anderen Artikel mit dem Jahresabo