Wenn Sie ein Abonnement des Magazins 'Access im Unternehmen' besitzen, können Sie sich anmelden und den kompletten Artikel lesen.
Anderenfalls können Sie das Abonnement hier im Shop erwerben.
Debugging-Hilfsfunktionen
Beim Debuggen von VBA-Code, der Anweisungen für den Zugriff auf die Daten der Anwendung per DAO enthält, benötigt man immer wieder mal Detailinformationen. Welche Felder enthält die Tabelle noch? Welchen Wert enthalten die Felder des aktuellen Datensatzes? Wie viele Datensätze liefert das aktuelle Recordset? Die notwendigen Informationen kann man sich mithilfe entsprechender Ausdrücke über das Direktfenster holen, aber meist kostet dies unnötig Zeit. Warum also nicht einfach eine kleine Hilfsklasse programmieren, die solche Fragen sehr einfach beantwortet? Dieser Beitrag zeigt, wie es gelingt.
Die Idee für diesen Betrag stammt aus meinen alltäglichen Bedürfnissen. Erstens habe ich wirklich oft den Bedarf, mal eben die Werte der Felder eines gerade in Bearbeitung befindlichen Datensatzes auszugeben oder auch nur dessen Feldnamen, zweitens kamen mit der Zeit noch weitere Ideen hinzu – abgeleitet zum Beispiel von MySQL, wo es einen einfachen Befehl etwa zur Anzeige aller Tabellen (ShowTables) oder zur Ausgabe der Beschreibung einer Tabelle gibt (Describe
Also habe ich eine Klasse entwickelt, die solche Fragen beantwortet. In den folgenden Abschnitten schauen wir uns an, wie die Klasse aufgebaut ist und welche Fragen sie beantworten kann.
Alle Tabellen ausgeben
Den Befehl ShowTables unter MySQL fand ich schon immer praktisch. Gerade wenn man nicht so oft mit einer Datenbank arbeitet, merkt man sich nicht unbedingt alle Tabellennamen – und zum Nachschlagen eines Tabellennamens immer vom VBA-Editor zum Access-Fenster zu wechseln macht auch keinen Spaß, vor allem, wenn der Navigationsbereich einige hundert Elemente enthält, durch die man sich erst mal zu den Tabellen durchkämpfen muss.
Also entwickeln wir zunächst einmal die Methode ShowTables, die eine Liste aller Tabellen der Datenbank in alphabetischer Reihenfolge im Direktfenster ausgeben soll.
Die Ausgabe könnte etwa wie in Bild 1 aussehen, sobald man den Befehl ShowTables dort eingibt und die Eingabetaste betätigt.
Bild 1: Ausgabe der Tabellen einer Datenbank mit DetailinformationenDafür benötigen wir natürlich eine entsprechende Prozedur, die Sie in Listing 1 finden. Die Prozedur verwendet eine Enumeration, die im gleichen Modul wie folgt deklariert wird:
Public Sub ShowTables(Optional intType As TableType, _ Optional bolSystem As Boolean = True, Optional bolHidden As Boolean = True)
Dim db As DAO.Database, rst As DAO.Recordset
Dim strType As String, strTable As String
Dim intLen As Integer
Dim strSystem As String, strHidden As String
Dim bolShow As Boolean
If intType = 0 Then intType = dbLocal + dbODBC + dbLinked
Set db = CurrentDb
Set rst = db.OpenRecordset("SELECT Name, Type FROM MSysObjects " _ "WHERE Type IN (1,4,6) ORDER BY Name", dbOpenDynaset)
intLen = DMax("Len(Name)", "MSysObjects")
Debug.Print
Debug.Print "Table" & Space(intLen - 4) & "Type"
Debug.Print String(intLen + 25, "-")
Do While Not rst.EOF
strTable = rst!Name & Space(intLen - Len(rst!Name))
bolShow = True
strSystem = ""
If (db.TableDefs(rst!Name).Attributes And dbSystemObject) Then
strSystem = "|System"
If bolSystem = False Then bolShow = False
End If
strHidden = ""
If (db.TableDefs(rst!Name).Attributes And dbHiddenObject) Then
strHidden = "|Hidden"
If bolHidden = False Then bolShow = False
End If
If bolShow = True Then
Select Case rst!Type
Case 1
If (intType And dbLocal) = dbLocal Then
strType = "Local Table"
Debug.Print strTable & " " & strType & strSystem & strHidden
End If
Case 4
If (intType And dbODBC) = dbODBC Then
strType = "ODBC Table"
Debug.Print strTable & " " & strType & strSystem & strHidden
End If
Case 6
If (intType And dbLinked) = dbLinked Then
strType = "Linked Table"
Debug.Print strTable & " " & strType & strSystem & strHidden
End If
End Select
End If
rst.MoveNext
Loop
End Sub
Listing 1: Ausgabe der Tabellen einer Datenbank im Direktfenster des VBA-Editors
Public Enum TableType
dbLocal = 1
dbODBC = 2
dbLinked = 4
End Enum
Die Enumeration stellt die Werte für den Parameter der Prozedur ShowTables bereit. Sie sollen mit der Prozedur nämlich nicht nur alle Tabellen ausgeben können, sondern auch nur alle lokalen Tabellen, alle ODBC-Tabellen oder auch nur die verknüpften Tabellen.
Um nur die lokalen Tabellen auszugeben, geben Sie etwa den folgenden Befehl im Direktfenster ein:
ShowTables dbLocal
Aber es gibt noch weitere Möglichkeiten, die auszugebenden Tabellen einzuschränken: Mit dem zweiten Parameter namens bolSystem legen Sie fest, ob Systemtabellen ausgegeben werden sollen. Der dritte Parameter bolHidden gibt schließlich an, ob auch versteckte Dateien in der Liste erscheinen sollen. Da beide Parameter standardmäßig auf den Wert True eingestellt sind, müssten Sie etwa den folgenden Aufruf verwenden, um nur die lokalen Tabellen ohne versteckte Tabellen und Systemtabellen auszugeben:
ShowTables dbLocal, False, False
Die Prozedur prüft zunächst, ob der Benutzer eines der Enumeration-Elemente zur Einschränkung des Tabellentyps angegeben hat. Falls nicht, ist intType = 0 und wir können intType per logischer Und-Verknüpfung auf alle Typen einstellen (dbLocal + dbODBC + dbLinked).
Danach öffnet die Prozedur ein Recordset mit allen Tabellen auf Basis der Systemtabelle MSysObjects. Man könnte zwar auch die TableDefs-Auflistung verwenden, um auf die Tabellen zuzugreifen, aber mit MSysObjects können wir die Tabellen direkt alphabetisch sortieren.
Die Abfrage enthält direkt einen Filter nach den entsprechenden Objekttypen – hier 1 für lokale Tabellen, 4 für ODBC-Tabellen und 6 für eingebundene Tabellen.
Damit wir eine saubere Darstellung in zwei Spalten erreichen, benötigen wir noch die maximale Länge der Tabellennamen. Diese holt die Prozedur mit einer DMax-Abfrage über den Ausdruck Len(Name) für die Tabelle MSysObjects.
Danach bildet die Prozedur die Spaltenüberschriften im Direktfenster ab, wobei nach einer Leerzeile die beiden Überschriften Table und Type folgen. Den Abstand dazwischen liefert die Space-Funktion, die den Text Type so platziert, dass er knapp rechts neben dem längsten Tabellennamen landet. Auch die Anzahl der als Linie dienenden Minuszeichen wird anhand der Länge des längsten Tabellennamens ermittelt.
Danach steigt die Prozedur in eine Do While-Schleife über alle Datensätze des Recordsets rst ein. Darin ergänzt sie den Inhalt des Feldes Name des Recordsets um die entsprechende Menge Leerzeichen, damit alle Tabellennamen die Länge des längsten Namens haben, und speichert das Ergebnis in der Variablen strTable.
Dann stellt sie die Variable bolShow auf True ein. Diese legt fest, ob die Tabelle aus dem aktuellen Datensatz ausgegeben wird, und kann in den folgenden Prüfungen noch auf False eingestellt werden.
Zunächst jedoch kümmern wir uns darum, ob es sich um eine Systemtabelle handelt. Zunächst gehen wir nicht davon aus und setzen die Variable strSystem auf eine leere Zeichenkette. Sollte die Tabelle sich allerdings als Systemtabelle herausstellen, was die Prozedur durch den Vergleich der Eigenschaft Attributes des entsprechenden Eintrags der Auflistung TableDefs mit der Konstanten dbSystemObject herausfindet, erhält strSystem den Wert |System. Dieser wird später an einen Ausdruck angehängt, der den Typ der Tabelle charakterisiert.
Sollte der Benutzer für den Parameter bolSystem jedoch den Wert False übergeben haben, was bedeutet, dass er keine Systemtabellen in der Ausgabeliste wünscht, stellt die Prozedur nun die Variable bolShow ebenfalls auf False ein.
Danach folgt das gleiche Spiel für versteckte Tabellen. Diesmal wird die Variable strHidden gegebenenfalls mit dem Wert |Hidden gefüllt, falls es sich bei der Tabelle um eine versteckte Tabelle handelt, und die Variable bolShow erhält den Wert False, wenn der Parameter bolHidden auch diesen Wert enthält.
Schließlich entscheidet der Wert von bolShow darüber, ob die Tabelle in der Ausgabe landet. Hat die Variable den Wert False, geschieht nichts weiter, anderenfalls werden die verschiedenen Tabellentypen anhand des Wertes des Feldes Type des Recordsets entweder ausgegeben oder nicht.
Schauen wir uns das für den ersten Case-Zweig der Select Case-Anweisung an: Hat rst!Type den Wert 1, was auf eine lokale Tabelle hindeutet, prüft die Prozedur durch eine logische Konjunktion, ob der mit intType übergebene Wert die Konstante dbLocal enthält (mehr über logische Konjunktionen erfahren Sie im Beitrag Rund um Binärzahlen, www.access-im-unternehmen.de/556).
In diesem Fall erhält die Variable strType den Wert Local Table. Außerdem gibt eine Debug.Print-Anweisung den Namen der Tabelle (zuzüglich der weiter oben hinzugefügten Leerzeichen) und die Inhalte der Variablen strType, strSystem und strHidden aus. Letztere könnten beispielsweise den Wert |Local Table|System|Hidden liefern, wenn es sich um eine lokale, versteckte Systemtabelle handelt.
Die beiden übrigen Case-Zweige erledigen dies ähnlich für ODBC-Tabellen und verknüpfte Tabellen.
Auf diese Weise gibt die Prozedur Informationen über alle Tabellen im Direktfenster aus.
Tabellenbeschreibungen
Die zweite Prozedur soll ähnliche Informationen liefern wie die Anweisung Describe
Das können wir allerdings auch: Die nachfolgend beschriebene Prozedur namens Describe liefert etwa die Ausgabe aus Bild 3.
Bild 3: Baugleiche Beschreibung im Direktbereich des VBA-EditorsDen ersten Teil der Prozedur, die diese Ausgabe liefert, finden Sie in Listing 2. Die Prozedur nimmt mit dem Parameter strTable den Namen der zu untersuchenden Tabelle entgegen. Sie füllt die Variable db mit einem Verweis auf die aktuelle Datenbank. Die Auflistung TableDefs dieses Objekts liefert dann mit dem Namen der Tabelle als Parameter ein TableDef-Objekt, das die Beschreibung der Tabelle sowie Auflistungen etwa der Tabellenfelder liefert. Dieses referenzieren wir mit der Variablen tdf.
Public Sub Describe(strTable As String)
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim fld As DAO.Field
Dim intLen As Integer, intLenDefault As Integer
Dim strType As String, strNull As String
Dim idx As DAO.Index
Dim fldidx As DAO.Field
Dim strIndex As String, strExtra As String
Set db = Currentdb
Set tdf = db.TableDefs(strTable)
For Each fld In tdf.Fields
If Len(fld.Name) > intLen Then
intLen = Len(fld.Name)
End If
If Len(fld.DefaultValue) > intLenDefault Then
intLenDefault = Len(fld.DefaultValue)
End If
Next fld
intLen = intLen + 2
If intLen < 16 Then
intLen = 16
End If
intLenDefault = intLenDefault + 2
If intLenDefault < 7 Then
intLenDefault = 7
End If
Debug.Print "Table" & Space(intLen - 5) _
& "| Type | NULL | Key | DEFAULT" & Space(intLenDefault - 7) _
& " | EXTRA"
Debug.Print "-----" & String(intLen - 5, "-") & "+---------------+------+-----+-" _
& String(intLenDefault - 7, "-") & "--------+------------------"
For Each fld In tdf.Fields
strType = ""
Select Case fld.Type
Case dbAttachment
strType = "ATTACHMENT"
Case dbBoolean
strType = "BOOLEAN"
Case dbCurrency
Dies war die Leseprobe dieses Artikels.
Melden Sie sich an, um auf den vollständigen Artikel zuzugreifen.