Zur Hauptseite ... Zum Onlinearchiv ... Zum Abonnement ... Zum Newsletter ... Zu den Tools ... Zum Impressum ... Zum Login ...

Achtung: Dies ist nicht der vollständige Artikel, sondern nur ein paar Seiten davon. Wenn Sie hier nicht erfahren, was Sie wissen möchten, finden Sie am Ende Informationen darüber, wie Sie den ganzen Artikel lesen können.

Kompletten Artikel lesen?

Einfach für den Newsletter anmelden, dann lesen Sie schon in einer Minute den kompletten Artikel und erhalten die Beispieldatenbanken.

E-Mail:

Gedrucktes Heft

Diesen Beitrag finden Sie in Ausgabe 6/2008.

Unser Angebot für Sie!

Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'!

Diesen Beitrag twittern

Zusammenfassung

Lernen Sie Möglichkeiten zum strukturierten Ablegen von Daten in Variablen kennen.

Techniken

VBA

Voraussetzungen

Access 2000 oder höher

Beispieldateien

collections.mdb

Shortlink

640

Arrays, Collections und Dictionarys

Sascha Trowitzsch, Berlin

Unter Access bietet sich das Speichern von Daten in Tabellen an. Die legen Sie in der Datenbankdatei an und greifen über gebundene Formulare, Berichte und Steuerelemente darauf zu. Unter VBA geschieht dies fast genauso bequem mithilfe von DAO- oder ADO-Recordsets. Manche Konstellationen schließen die Verwendung von gebundenen Recordsets aus und Sie müssen auf andere Strukturen zum temporären Speichern Ihrer Daten zurückgreifen. Dieser Beitrag stellt die verschiedenen Möglichkeiten und ihre Vor- und Nachteile vor.

Wollen Sie nur eine einzige Information wie etwa den Namen einer Person so festhalten, dass Sie jederzeit schnell darauf zugreifen können, reicht eine simple String-Variable aus:

Dim strName As String

strName = "Sascha Trowitzsch"

Sobald Sie mehrere Daten zu einer Einheit zusammenfassen möchten, helfen die Standarddatentypen nicht mehr weiter. Hier können Sie benutzerdefinierte Strukturen mit einem festen Aufbau verwenden, deren Definition etwa so aussieht:

Type TPerson

Vorname As String

Nachname As String

Geburtsdatum As Date

End Type

Um diese Struktur einzusetzen, deklarieren Sie eine Variable auf Basis der Struktur und füllen deren Element wie in den folgenden Beispielanweisungen:

Dim Autor As TPerson

Autor.Vorname = "Sascha"

Autor.Nachname = "Trowitzsch"

Autor.Geburtsdatum = "11.1.1918"

Damit stoßen Sie spätestens dann an Ihre Grenzen, wenn Sie mehrere gleichartige Daten in einer Liste zusammenfassen wollen - im Beispiel etwa eine Gruppe von Personen. Dann benötigen Sie ein Datenfeld, wobei einem als Erstes das Array einfällt. Tatsächlich gibt es unter Access und VBA aber noch einige Möglichkeiten mehr:

  • Arrays
  • Collections
  • Dictionarys
  • TempVars (nur Access 2007)
  • ADODB-Recordsets
  • API-SafeArrays

Die ersten fünf Varianten stellen wir in den folgenden Abschnitten vor, die sechste würde leider den Rahmen dieses Beitrags sprengen.

ADODB-Recordsets

Wenn man an ADO-Recordsets denkt, zieht man direkt Parallelen zu ihrem DAO-Pendant und damit zur Bindung an Tabellen. Im Gegensatz zu DAO benötigt ein ADO-Recordset jedoch nicht zwingend einen Bezug zu einer physischen Datenherkunft und kann als reiner Datencontainer im Speicher dienen. Solche Recordsets, in denen die Eigenschaft Connection nicht gesetzt ist, nennt man auch ungebundene Recordsets (es gibt auch noch die Disconnected Recordsets, die zunächst mit Daten etwa aus einer Tabelle gefüllt und dann von dieser getrennt werden - mehr dazu im Beitrag Disconnected Recordsets, Shortlink 437).

Listing 1 zeigt beispielhaft, wie Sie solch ein ungebundenes Recordset anlegen und füllen.

<

Listing 1: Disconnected ADODB-Recordset als Variablenspeicher

Sub ADODBCollection()

    Dim rst As ADODB.Recordset

    Set rst = New ADODB.Recordset

    rst.CursorLocation = adUseClient

    rst.Fields.Append "Nachname", adBSTR

    rst.Fields.Append "Vorname", adBSTR

    rst.Fields.Append "Geburtsdatum", adDate

    rst.Open , , adOpenKeyset

    rst.AddNew

    rst!Nachname = "Trowitzsch"

    rst!Vorname = "Sascha"

    rst!Geburtsdatum = "11.1.1918"

    rst.MoveFirst

    rst.Find "Nachname='Trowitzsch'"

    If Not rst.EOF Then

        Debug.Print rst(0), rst(1), rst(2)

    End If

    rst.Close

    End Sub

Wichtig ist hier die Open-Methode des Recordsets, die den Connection-Parameter auslässt, wodurch das Recordset keinerlei Bezug zu einer Tabelle der Datenbank selbst hat. Bei einem Disconnected Recordset bindet man das Recordset zunächst an eine Tabelle und deaktiviert anschließend die Verbindung:

Set rst.Connection = Nothing

Danach hat man wieder ein rein speicherbasiertes Recordset, in dem Sie Daten ändern können, ohne dass sich dies auf die Daten aus der Herkunftstabelle niederschlägt.

Das große Plus von ADODB ist seine hohe Flexibilität. Das Recordset lässt verschiedenste Operationen zu, wobei gerade die Suchmöglichkeiten einen wesentlichen Vorteil gegenüber den weiter unten vorgestellten Arrays und Collections ausmachen. Das hat jedoch seinen Preis: Der Verwaltungsaufwand für das Objekt und seine Schnittstelle ist hoch, was zulasten der Performance geht. Wer Millionen Berechnungen auf Basis der Elemente dieses Datencontainers ausführen möchte, wird am ADODB-Recordset keine rechte Freude haben.

Zum Einsatz kommen ungebundene Recordsets als reiner Variablenspeicher daher vor allem, wenn kompliziertere Operationen ausgeführt werden sollen, die sich mit Arrays und Collections nur durch hohen Programmieraufwand realisieren ließen.

TempVars

Mit Access 2007 hat Microsoft einen neuen Typ von Auflistungsvariablen eingeführt: die TempVars. Es handelt sich dabei um ein eindimensionales Array, das allerdings eher einer Collection ähnelt, weil Sie dessen Elemente über einen Key ansprechen können. Speichern können Sie in TempVars jedoch nur Standarddatentypen, aber keine Objekte, Arrays oder benutzerdefinierte Typen.

TempVars müssen Sie nicht extra als Variable deklarieren, weil Access die Auflistung von vornherein als Eigenschaft des Application-Objekts mitbringt. Neue Elemente fügen Sie etwa so hinzu:

TempVars.Add "Nachname", "Trowitzsch"

TempVars.Add "Vorname", "Sascha""

TempVars.Add "Geburtsdatum", CDate("1.11.1918")

TempVars("Vorname") = "Alexander" 'Inhalt ändern

Debug.Print TempVars("Vorname")

Das ist eine komfortable Möglichkeit, Daten schnell und ohne großen Aufwand in einem Datenfeld zu speichern. TempVars haben zudem eine ganz besondere Eigenschaft: Sie gehen nicht verloren. Während globale Variablen beim Auftreten eines nicht behandelten Fehlers unter VBA grundsätzlich zerstört werden, bleiben TempVars erhalten. Sie sind damit sichere Datenspeicher und wickeln ihre Geschäfte zudem recht flott ab. Die Performance der Auflistung beim Zugriff auf die enthaltenen Elemente ist sehr gut.

Andererseits sind die Features nicht gerade atemberaubend. Ein Knackpunkt etwa ist die fehlende Möglichkeit, neue TempVars-Variablen anzulegen. Man ist auf die eine eingebaute und flache Liste angewiesen. Damit eignen sich TempVars in erster Linie zum Speichern anwendungsbezogener Daten, in denen Sie beispielsweise einzelne Einstellungen unterbringen möchten.

Arrays

Der klassische Variablentyp zur Speicherung mehrerer Elemente ist das Array. Es kann beliebige Datentypen aufnehmen, also auch Objekte und benutzerdefinierte Typen und arbeitet wegen seines einfachen Aufbaus außerordentlich schnell.

Das Beispiel aus Listing 2 speichert mehrere der in einem früheren Beispiel angelegten Type-Strukturen in Form einer Personenliste.

<

Listing 3: Variablen setzen mit DAO

Sub SetVarDAO(ByVal strVarName As String, Wert As Variant)

    With rstVars

    .FindFirst "VarName='" & strVarName & "'"

    If .NoMatch Then

        .AddNew

        !VarName = strVarName

    Else

        .Edit

    End If

    !VarWert = CStr(Wert)

    .Update

    End With

    End Sub

Einige Besonderheiten sind im Umgang mit Arrays zu beachten:

  • Die Zahl der enthaltenen Elemente können Sie zwar schon bei der Deklaration der Variable voreinstellen (statisches Array), günstiger ist jedoch die Deklaration als dynamisches Array ohne Angabe der Dimensionen. Diese können Sie jederzeit ändern, was bedeutet, dass Sie beispielsweise nachträglich neue Elemente hinzufügen können. Anfangs initialisieren Sie das dynamische Array daher mit einem einzigen Element: ReDim arrPerson(0)
  • Wenn Sie neue Elemente in ein dynamisches Array aufnehmen, müssen Sie es zuvor neu dimensionieren. Damit bei diesem Vorgang nicht alle bereits gespeicherten Elemente verloren gehen, fügen Sie das Schlüsselwort Preserve ein: ReDim Preserve arrPerson(1)
  • Der Zugriff auf Elemente des Arrays geschieht immer über ihre Ordinalzahl, also den Index des Elements. Sie können ein Element nicht wie bei Collection- und Dictionary-Auflistungen über einen Schlüssel ansprechen. Damit entfällt auch eine gezielte Suche nach Elementen, sodass Sie Suchmechanismen selbst programmieren müssen.
  • Die Elemente eines Arrays können Sie über die Direktive Erase leeren. Das ist gerade beim Speichern von Objekten im Array wichtig, weil Erase dann alle Objektbezüge auf Nothing setzt. Somit bestehen keine Referenzen auf die Ursprungsobjekte mehr, die dazu führen könnten, dass diese im Speicher verbleiben.

Die Zahl der Elemente fragen Sie mit der Funktion UBound ab:

Debug.Print UBound(arrPerson) + 1

Da UBound den Index des letzten Elements zurückgibt, das Array normal aber nullbasiert ist, ergibt sich die Anzahl aus dem höchstem Index plus eins. Ist das Array noch gar nicht dimensioniert worden, liefert der Aufruf von UBound nicht etwa den Wert 0, sondern löst einen Fehler aus.

Arrays können auch andere Arrays als Elemente aufnehmen. Dadurch ist, vor allem im Zusammenspiel mit benutzerdefinierten Typen, der Aufbau von Strukturen möglich. So einfach und schnell solche Gebilde auch sind, ein Manko haftet ihnen doch an: Um ein Element im Array zu finden, müssen Sie leider alle Elemente in einer Schleife durchlaufen und mit einer Suchvariablen vergleichen. Der Zeitaufwand für die Suche steigt damit linear mit der Anzahl der Elemente.

Nehmen wir an, Sie hätten im Array des Beispiels aus Listing 2 genau 100 Personen gespeichert. Um nun den Vornamen der Person Müller zu erfahren, müssen Sie alle Nachnamen-Elemente des Arrays mit diesem Suchbegriff vergleichen, um schließlich nach dem hundertsten Durchlauf Gleichheit festzustellen. Über den nun ermittelten Index des gefundenen Elements erhalten Sie den Vornamen:

strFind = "Müller"

For i = 0 To UBound(arrPerson)

    If arrPerson(i).Nachname = strFind Then

        Debug.Print arrPerson(i).Vorname

        Exit For

    End If

Next i

Unter Performance-Gesichtspunkten ist also die Verwendung von Arrays kontraindiziert, wenn gezielt Elemente bearbeitet werden sollen.

Collections

Collections brauchen Sie im Gegensatz zu Arrays nicht zu dimensionieren. Sie erleichtern die Suche nach Elementen über ihren Schlüssel (Key). Man spricht deshalb bei Collections und ihren Derivaten auch von assoziativen Arrays. Eine Collection-Variable ist schnell angelegt und gefüllt:

Sub PersonenCollection()

    Dim colPersonen As VBA.Collection

    Set colPersonen = New VBA.Collection

    With colPersonen

    .Add "Minhorst", "Nachname"

    .Add "André", "Vorname"

    .Add CDate("26.05.1929"), "Geburtsdatum"

    Debug.Print "Anzahl Elemente:" & .Count

    Debug.Print !Nachname

    End With

    Debug.Print colPersonen(2)

    Set colPersonen = Nothing

    End Sub

Weitere Bemerkungen zum Collection-Objekt:

  • Eine Collection instanzieren Sie per New-Anweisung. Vermeiden Sie, das bereits bei Deklaration der Variablen zu tun, weil damit immer unklar ist, in welchem Zustand sie sich befindet. Gelöscht wird die Instanz mit Setzen auf Nothing.
  • Elemente fügen Sie mit der Add-Methode hinzu, wobei Sie einen Schlüssel zur späteren Identifizierung hinzugeben können. Ohne den Schlüssel ist der Zugriff dann nur noch über den Index, also die Position des Elements im Array, möglich.
  • Ein Element können Sie auch zwischen bestehenden Elementen einfügen. Sie müssen dazu die optionalen Parameter before und after angeben. Erläuterungen finden Sie in der Visual Basic-Hilfe.
  • Ein Element können Sie über drei Syntaxarten direkt abfragen: Collection("Schlüssel"), Collection!Schlüssel oder Collection(Index)
  • Der Zugriff auf die Elemente über den Ordinalindex beginnt im Unterschied zu Arrays mit dem Index 1 und nicht mit 0. Das erste Element im Beispiel ist colPersonen(1).
  • Ein einmal hinzugefügtes Element können Sie nicht mehr verändern.

Sie haben das Ende des frei verfügbaren Teils des Artikels erreicht. Lesen Sie weiter, um zu erfahren, wie Sie den vollständigen Artikel lesen und auf viele hundert weitere Artikel zugreifen können.

Sind Sie Abonnent?Jetzt einloggen ...
 

Kompletten Artikel lesen?

Einfach für den Newsletter anmelden, dann lesen Sie schon in einer Minute den kompletten Artikel und erhalten die Beispieldatenbanken.

E-Mail:

Verwandte Beiträge:

Verwaltung von Daten ohne Tabelle

Performanter Webzugriff auf MySQL-Datenbanken

Schnelle Domänenfunktionen

Access-Optionen gestern und heute

Temporäre Datensatzgruppen

Kontextmenüs von A bis Z

Indizierung mit Access

Das Append-Only-Memofeld

Access 2007: Bilder und Schaltflächen

© 2003-2015 André Minhorst Alle Rechte vorbehalten.