Tabellen und Abfragen über DAO verwalten

Der Umgang mit den Datensätzen einer Tabelle über das Recordset-Objekt der DAO-Bibliothek ist das A und O der Programmierung unter Access und dürfte Ihnen deshalb wahrscheinlich geläufig sein. Nicht selten aber wird auch der Zugriff auf die Eigenschaften der Tabellen und Abfragen selbst benötigt – und hier kommt abermals DAO mit seinen TableDef- und QueryDef-Objekten ins Spiel.

Beispieldatenbank

Die Beispiele dieses Artikels finden Sie in der Datenbank 1501_DAO.mdb.

Tabellen und Abfragen im Objektmodell von DAO

Access legt beim Erstellen einer Datenbankdatei automatisch einen Verweis auf die DAO-Bibliothek im VBA-Projekt an, weil ohne sie keine Möglichkeit besteht, an die Datenobjekte heranzukommen. Zwar gibt es auch eine weitere Bibliothek namens ADODB, die ersatzweise verwendet werden kann, doch diese wird inzwischen von Microsoft weder weiterentwickelt, noch empfohlen. Sie war einst in erster Linie für den erweiterten Zugriff auf den SQL-Server gedacht, als Access 2000 mit den Access-Projekten (ADP) aufwartete. Doch da diese etwa von Access 2013 gar nicht mehr unterstützt werden, gibt es auch keinen triftigen Grund mehr, diese Bibliothek einzusetzen.

DAO als Abkürzung für Data Access Objects ist nur der Modellname der Bibliothek. In der Liste der Verweise finden Sie sie jedoch unter der monströsen Bezeichnung Microsoft Office 14.0 Access database engine Object Library, wobei sich das je nach Version von Access geringfügig unterscheidet. Vor Access 2007 lautete die Bezeichnung allerdings tatsächlich Microsoft DAO 3.6 Object Library.

öffnen Sie im VBA-Editor über das Menü Ansicht den Objektkatalog und wählen aus dem Kombinationsfeld oben links den Eintrag DAO aus, wie in Bild 1. Der Katalog füllt sich dann mit allen Objektklassen, die die Datenzugriffsbibliothek aufweist, bei denen die Klasse Database von zentraler Bedeutung ist und quasi das Ebenbild der Datenbank ausmacht. Beim Klicken auf diese Klasse zeigen sich im rechten Abteil die Methoden und Eigenschaften des Database-Objekts. Da uns für das Thema dieses Beitrags nun besonders die Tabellen und Abfragen interessieren, die in einer Datenbank enthalten sind, müsste das Database-Objekt wohl irgendwelche Methoden aufweisen, um auf diese zugreifen zu können. Tatsächlich ist das mit den beiden Auflistungseigenschaften TableDefs und QueryDefs gegeben, die in Bild 1 markiert wurden. Sie sind beide Container für die einzelnen Tabellen- und Abfragen-Objekte. Dabei steht TableDef für “Tabellendefinition” und QueryDef für “Abfragedefinition”.

DIe DAO-Bibliothek im VBA-Objektkatalog

Bild 1: DIe DAO-Bibliothek im VBA-Objektkatalog

Nehmen wir uns zunächst die Aufgabe vor, über diese DAO-Klassen alle Tabellen aufzulisten, die die aktuelle Datenbank enthält. Als Erstes braucht es dafür ein Database-Objekt, von dem sich dann die TableDefs-Auflistung ableitet. Allerdings ist Database ja nur eine Modellklasse und noch kein Objekt – eine Klasse muss erst in Form einer Objektvariablen instanziiert werden. Und da die DAO-Bibliothek eine externe Komponente ist, die lediglich als Modell in das VBA-Projekt eingeklinkt ist, weiß sie eigentlich auch gar nichts von der Access-Datenbank, in der sie untergebracht wurde. Es muss also ein Bezug zu einem Database-Objekt hergestellt werden, das Access bereitstellt. Das tut es auch mit der Eigenschaft CurrentDb des Access-Application-Objekts:

Dim dbs As Database
Set dbs = Application.CurrentDb

Das Application kann auch weggelassen werden, da es sich um eine globale Eigenschaft von Access handelt.

Auch das übertragen auf eine Objektvariable dbs ist nicht zwingend notwendig, da CurrentDb jederzeit erneut abgefragt werden kann. Neben CurrentDb gibt es noch eine weitere Variante der Zuweisung:

Set dbs = Application.DbEngine(0)(0)

Die Nullen in Klammern sind eine zulässig abgekürzte Form von

Dbengine.Workspaces(0).Databases(0)

Nachdem nun ein gültiges Database-Objekt vorliegt, kann es auch an die Liste der Tabellen gehen:

 CurrentDb.TableDefs.Count

Das gibt die Anzahl der in der Datenbank enthaltenen Tabellen im Direktfenster aus. Analog geht das für die Abfragen mit

 CurrentDb.QueryDefs.Count

Damit Sie nicht spekulieren müssen, wie mit diesen Auflistungen weiter verfahren wird, sind in Bild 2 deren Methoden aus dem Objektkatalog dargestellt.

Methoden der TableDefs- und QueryDefs-Auflistungsklassen

Bild 2: Methoden der TableDefs- und QueryDefs-Auflistungsklassen

Count ermittelt die Anzahl der jeweiligen Objekte. Delete löscht ein Element. Da ein TableDef-Objekt direkt an die zugehörige Tabelle gekoppelt ist, bedeutet Löschen hier, dass auch die Tabelle aus der Datenbank entfernt wird:

Currentdb.TablesDefs.Delete "Tabelle1"

Tabelle1 wandert damit ins Nirwana. Append würde eine Tabelle zur Datenbank hinzufügen. Das Vorgehen ist hier allerdings nicht so einfach, wie beim Löschen, denn Append erwartet ein fertiges TableDef-Objekt, das erst über die Database-Methode CreateTableDef erzeugt und mit allerlei weiteren Eigenschaften, wie Feldern, versehen sein muss. Tabellen über VBA anlegen zu müssen, dürfte jedoch ziemlich selten vorkommen, so dass dies hier nicht weiter besprochen wird.

Refresh ist eine Methode, die die Auflistung auf den neuesten Stand bringt. Löschen Sie etwa eine Tabelle per Delete, so findet sie sich zunächst trotzdem noch in der Auflistung. Erst ein Refresh aktualisiert die Liste wieder.

Item schließlich ist der Bezug zu einem einzelnen TableDef-Objekt, das über den Index der Auflistung angesprochen wird:

CurrentDb.TablesDefs.Item(0)

Hier erhält man das TableDef-Objekt, welches auf die erste Tabelle der Datenbank verweist. Weil Item die sogenannte Default-Eigenschaft der Klasse ist, erkennbar am blauen Punkt im Objektkatalog, kann der Methodenname auch weggelassen werden:

Dim tdf As TableDef
Set tdf = CurrentDb.TableDefs(0)

Außerdem kann auch direkt der Name des Objekts als Index statt der Ordinalzahl verwendet werden:

CurrentDb.TableDefs("Tabelle1")

Mit diesem Wissen könnten Sie bereits die Routine zum Ausgeben aller Tabellen der Datenbank anfertigen. Es muss nur die Zahl der TableDefs mit Count ermittelt und dann in einer Schleife über eine Zählervariable n jedes Objekt mit Item(n) angesprochen werden. Name ist die Eigenschaft des TableDef-Objekts, welches auch dem Namen der Tabelle entspricht.

Es geht aber noch einfacher. Weil die Auflistungen COM-Enumeration unterstützen, kann man auf das Ansprechen per Index verzichten und eine For..Each-Schleife einsetzen. Der Beispielcode steht in Listing 1. Im VBA-Direktfenster wird erst die Zahl der Tabelle ausgegeben, danach jedes Element der Auflistung durchlaufen und der Name der entsprechenden Tabelle angezeigt.

Sub ListTables()
     Dim tdf As DAO.TableDef
     
     Debug.Print CurrentDb.TableDefs.Count & " Tabellen"
     For Each tdf In CurrentDb.TableDefs
         Debug.Print tdf.Name
     Next tdf
     
End Sub

Listing 1: Ausgeben aller Tabellen der Datenbank über die TableDefs-Auflistung

Wie aus Bild 2 hervorgeht, gleichen sich die Auflistungen für TableDefs und QueryDefs vollständig. Deshalb ist der Code zur Ausgabe aller Abfragen ebenfalls identisch (Listing 2).

Sub ListQueries()
     Dim qdf As DAO.QueryDef
     
     Debug.Print CurrentDb.QueryDefs.Count & " Abfragen"
     For Each qdf In CurrentDb.QueryDefs
         Debug.Print qdf.Name
     Next qdf
     
End Sub

Listing 2: Ausgeben aller Abfragen der Datenbank über die QueryDefs-Auflistung

Das TableDef-Objekt

Hat man erst einmal ein TableDef-Objekt, so lässt sich damit natürlich noch mehr anstellen, als nur die Ausgabe des Tabellennamens. Eine übersicht aller Methoden sowohl der TableDef– als auch der QueryDef-Klassen zeigt der kombinierte Screenshot des Objektkatalogs in Bild 3. Einige davon sind nur für sehr spezielle Aufgaben von Belang, etwa für Tabellen, die über ODBC in die Datenbank verknüpft sind, oder PassThrough-Abfragen, die ebenfalls auf einen SQL-Server aufsetzen. Gleiches gilt für Tabellen, die in Datenbanken mit Replikation vorkommen – teilweise Features, die die aktuellen Versionen von Access gar nicht mehr unterstützen! Diese Methoden sind der Kompatibilität wegen noch im Objektmodell vorhanden, geben meist aber gar keine Werte mehr zurück. In Bild 3 sind alle Methoden, die Sie kaum interessieren dürften, grau hinterlegt.

TableDef- und QueryDef-Methoden

Bild 3: TableDef- und QueryDef-Methoden

Im Folgenden werden die relevantesten Methoden der TableDef-Klasse angeführt. Alles Weitere erfahren Sie in der Hilfe zu DAO, die allerdings leider nicht automatisch mit den neueren Access-Versionen installiert wird. Es gibt auch keine aktualisierte Hilfedatei zu DAO seit Access 2003. Deshalb gelangen Sie auch nicht zur Hilfe, wenn Sie etwa in Listing 2 den Ausdruck QueryDef markieren und F1 drücken. Denn in das Objektmodell ist nach wie vor ein Bezug zur Hilfedatei DAO360.chm gespeichert, der ins Leere führt, wenn sich diese Datei nicht auf ihrem System befindet.

Wenn Sie die kontextsensitive Hilfe verwenden wollen, so besorgen Sie sich diese Hilfedatei im Internet und speichern sie im Windows-Verzeichnis im Unterordner Help. Ansonsten sind Sie darauf angewiesen, die Hilfe zu Access-VBA über das Menü des VBA-Editors aufzurufen und dann in der Access Entwicklerreferenz den Zweig Microsoft-Datenzugriffsobjekte (DAO)-Referenz zu erforschen. Zurück zu den TableDef-Methoden:

DateCreated gibt zurück, wann eine Tabelle erstellt, LastUpdated den Zeitpunkt, wann sie zuletzt im Entwurf aktualisiert wurde. Fields, Indexes und Properties sind Auflistungseigenschaften, auf die wir noch gesondert zu sprechen kommen.

RecordCount ist eine interessante Eigenschaft: Sie zeigt die Zahl der in der Tabelle gespeicherten Datensätze an, soweit es sich um eine nicht-verknüpfte Tabelle handelt.

Im Gegensatz zu den missverständlichen Erläuterungen der DAO-Hilfe stimmt diese Zahl immer, auch wenn nicht, wie dort angeführt, bereits erst auf alle Datensätze zugegriffen wurde. Dies gilt nur für ein Recordset-Objekt.

Updatable kennzeichnet, ob der Inhalt einer Tabelle schreibgeschützt ist, oder aktualisierbar. Für die Systemtabellen wird hier in der Regel ein False zurückgegeben.

ValidationRule und ValidationText sind Synonyme für die Gültigkeitsregel einer Tabelle und die gegebenenfalls ausgegebene Meldung. Das sind Eigenschaften, von denen selten Gebrauch gemacht wird, da Gültigkeitsbeschränkungen meist auf Feldebene definiert werden.

Die Create-Methoden korrelieren mit den entsprechenden Auflistungen zu Fields, Indexes und Properties. Hierüber können neue Felder in einer Tabelle erzeugt, neue Indizes oder neue benutzerdefinierte Eigenschaften hinzugefügt werden.

Connect und RefreshLink haben nur Bedeutung im Zusammenhang mit verknüpften Tabellen. In Connect wird der Pfad zu einer Backend-Datenbank angegeben und mit RefreshLink erst wirklich aktualisiert. Alle anderen Tabellen zeigen für Connect einen leeren String.

OpenRecordset öffnet eine Datensatzgruppe auf die Tabelle. Das dürfte Ihnen bekannt vorkommen. Hier handelt es sich um eine Alternative zur Syntax mit

CurrentDb.OpenRecordset("tblXY")

Dasselbe Ergebnis erhalten Sie mit

Dim tdf As TableDef
Set tdf = CurrentDb.TableDefs("tblXY")
tdf.OpenRecordset

Beide Varianten sind in Listing 3 aufgeführt. Im ersten Teil kommt die konventionelle Methode zum Einsatz, im zweiten das TableDef-Objekt. Eigentlich gibt es keinen Grund, zu dieser Variante zu greifen. Sie ist hier aber aufgeführt, weil sie so schön zwei VBA-Spezialitäten demonstriert: Einmal die With-Anweisung – in dieser Ausgabe bereits besprochen – und dann die Gültigkeit eines Objekts. Machen Sie den Versuch und schreiben zum Setzen der TableDef-Variablen diesen Code:

Set tdf = _
     CurrentDb.TableDefs("tblLaender")
Set rs = tdf.OpenRecordset()

Während die erste Zeile noch anstandslos ausgeführt wird, kommt es bei der zweiten Zeile zu der Fehlermeldung, dass ein Objekt nicht mehr festgelegt sei. Dass die tdf-Variable nicht der übeltäter sein kann, erfahren Sie über den Test im Direktfenster, nachdem Sie einen Haltepunkt auf die Zeile setzten:

 tdf.Name

gibt korrekt tblLaender zurück. Was aber sollte dann nicht festgelegt sein Es bleibt nur noch das CurrentDb-Objekt. Tatsächlich handelt es sich bei diesem um ein nichtpersistentes Objekt, welches nur eine Momentaufnahme der aktuellen Datenbank versinnbildlicht. In der zweiten Code-Zeile ist es sozusagen bereits wieder verschwunden. Die übliche Lösung für diesen Umstand besteht im zusätzlichen Anlegen einer Database-Variablen:

Dim dbs As Database
Set dbs = CurrentDb
Set tdf = dbs.TableDefs("tblLaender")

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access [basics]:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 400 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar