Mit Arrays arbeiten

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.

Mit Arrays arbeiten

Über Arrays unter VBA wurde schon vieles geschrieben und gesagt. Dennoch gibt es praktische Hinweise, die man gelegentlich benötigt, nicht so einfach im Internet. Also werfen wir in diesem Beitrag einen genaueren Blick auf die Möglichkeiten, die Arrays bieten, und liefern einige neue Funktionen rund um die Felder zum temporären Speichern und Bereitstellen von Daten. Unter anderem sehen wir uns an, wie Sie die Inhalte von Arrays zu Debugging-Zwecken im Direktbereich oder in einer Excel-Tabelle ausgeben oder wie Sie prüfen, ob ein Array leer ist.

Array aus Datensatz füllen

Manchmal möchten Sie vielleicht die Daten eines oder mehrerer Felder eines Datensatzes in einem Array speichern, um diese Daten performant bereitzustellen.

Wenn Sie nur ein Feld eintragen möchten, reicht ein eindimensionales Array aus. Dieses füllen Sie mithilfe der Funktion RecordsetInArrayEindimensional aus Listing 1. Die Funktion erwartet das einzulesende Recordset mit dem Parameter rst.

Public Function RecordsetInArrayEindimensional(rst As DAO.Recordset) As Variant()
     Dim arr() As Variant
     Do While Not rst.EOF
         ReDim Preserve arr(rst.AbsolutePosition)
         arr(rst.AbsolutePosition) = rst.Fields(0).Value
         rst.MoveNext
     Loop
     RecordsetInArrayEindimensional = arr
End Function

Listing 1: Einlesen eines Feldes eines Recordsets in ein eindimensionales Array

Es deklariert ein Array namens arr mit dem Datentyp Variant. In einer Do While-Schleife durchläuft die Funktion alle Datensätze des Recordsets und führt dabei zwei Anweisungen aus:

  • das ReDimensionieren des Arrays entsprechend der aktuellen Position des Datensatzzeigers (AbsolutePosition) sowie
  • das Zuweisen des Werts des ersten Felds des aktuellen Datensatzes an die entsprechende Position des Arrays.

Danach übergibt die Funktion das Array als Funktionswert an die aufrufende Routine. Diese sieht beispielsweise wie in Listing 2 aus. Die Routine füllt das Recordset-Objekt mit den Datensätzen der Tabelle tblArtikel, wobei nur das Feld Artikelname berücksichtigt wird.

Public Sub Test_RecordsetInArray()
     Dim db As DAO.Database
     Dim rst As DAO.Recordset
     Dim i As Integer
     Dim arr() As Variant
     Set db = CurrentDb
     Set rst = db.OpenRecordset("SELECT Artikelname FROM tblArtikel", dbOpenDynaset)
     arr = RecordsetInArrayEindimensional(rst)
     For i = LBound(arr) To UBound(arr)
         Debug.Print arr(i)
     Next i
End Sub

Listing 2: Test zum Einlesen eines eindimensionalen Arrays aus einem Recordset

Dann ruft sie die Funktion Recordset­In­ArrayEindimensional auf und übergibt das Recordset als Parameter.

Um zu prüfen, ob alle Werte wie gewünscht in das Array eingelesen wurden, durchläuft die Routine anschließend in einer For...Next-Schleife alle Elemente des Arrays und gibt den jeweils aktuellen Wert im Direktbereich des VBA-Editors aus.

ReDim vorziehen

Wenn schon vorher klar ist, wie viele Elemente im Array landen sollen, können Sie dieses natürlich auch bereits vor dem Eintritt in die Do While-Schleife redimensionieren.

Der Versuch, dies direkt beim Deklarieren des Arrays zu erledigen, schlägt allerdings fehl – mit der Fehlermeldung Konstanter Ausdruck erforderlich, wie in Bild 1 zu erkennen.

Automatische Ergänzung eines Feldnamens

Bild 1: Automatische Ergänzung eines Feldnamens

Also deklarieren wir das Array in einer neuen Version der Funktion (s. Listing 3) zunächst ohne Angabe der Anzahl der enthaltenen Elemente und ändern diese dann später mit der ReDim-Anweisung. Dieser übergeben wir den Ausdruck rst.RecordCount. Damit diese Eigenschaft des Recordsets immer den richtigen Wert liefert, verschieben wir den Datensatzzeiger zuvor mit MoveLast einmal an das Ende der Datensatzgruppe und mit MoveFirst wieder an die erste Position.

Public Function RecordsetInArrayEindimensional(rst As DAO.Recordset) As Variant()
     Dim arr() As Variant
     rst.MoveLast
     rst.MoveFirst
     ReDim arr(rst.RecordCount - 1)
     Do While Not rst.EOF
         arr(rst.AbsolutePosition) = rst.Fields(0).Value
         rst.MoveNext
     Loop
     RecordsetInArrayEindimensional = arr
End Function

Listing 3: Einlesen eines eindimensionalen Arrays mit vorheriger Dimensionierung

Im Gegensatz zum ReDimensionieren innerhalb der Do While-Schleife entfällt hier natürlich das Preserve-Schlüsselwort der ReDim-Anweisung, denn das Array ist ja ohnehin noch leer.

Gleichzeitig beheben wir noch einen kleinen Fehler bei der Dimensionierung: Dort haben wir nämlich zunächst den Wert von rst.RecordCount als Obergrenze angegeben. Die Untergrenze ist jedoch, wenn nicht anders angegeben, 0. Das heißt, dass wir das Array um ein Element zu groß dimensionieren würden. Also ändern wir den Ausdruck für die obere Grenze in rst.RecordCount - 1.

Mehrdimensionale Arrays mit Daten füllen

Wenn Sie nun mehrere Felder in das Array einlesen möchten, müssen Sie dieses entsprechend anders dimensionieren – nämlich als zweidimensionales Array. Dazu deklarieren wir in der Funktion RecordsetInArrayMehrdimensional zunächst wieder das Array arr (s. Listing 4). Anschließend redimensioniert die Funktion es, und zwar mit der Anzahl der Datensätze in der ersten Dimension und mit der Anzahl der Felder in der zweiten. Danach durchläuft die Funktion in einer äußeren Do While-Schleife die Datensätze des Recordsets und in einer inneren Schleife die Felder – und zwar über die Fields-Auflistung des Recordsets. Innerhalb der Schleife füllt die Funktion das Array. Da fld keinen Index mitliefert, müssen wir immer noch umständlich eine Zählervariable namens i mitlaufen lassen, um die Position für die zweite Dimension anzugeben. Dies können wir auch noch eleganter erledigen, indem wir die innere Schleife als For...Next- statt als For...Each-Schleife implementieren:

Public Function RecordsetInArrayMehrdimensional(rst As DAO.Recordset) As Variant()
     Dim arr() As Variant
     Dim fld As DAO.Field
     Dim i As Integer
     rst.MoveLast
     rst.MoveFirst
     ReDim arr(rst.RecordCount - 1, rst.Fields.Count - 1)
     Do While Not rst.EOF
         For Each fld In rst.Fields
             i = 0
             arr(rst.AbsolutePosition, i) = fld.Value
             i = i + 1
         Next fld
         rst.MoveNext
     Loop
     RecordsetInArrayMehrdimensional = arr
End Function

Listing 4: Einlesen eines mehrdimensionalen Arrays mit vorheriger Dimensionierung

Do While Not rst.EOF
     For i = 0 To rst.Fields.Count - 1
         arr(rst.AbsolutePosition, i) _
             = rst.Fields(i)
     Next i
     rst.MoveNext
Loop

Die Funktion zum Testen dieser Funktion finden Sie in Listing 5. Die Prozedur erstellt diesmal ein Recordset mit den beiden Feldern ArtikelID und Artikelname der Tabelle tblArtikel und übergibt dieses als Parameter an die Funktion RecordsetInArrayMehrdimensional.

Public Sub Test_RecordsetInArrayMehrdimensional()
     Dim db As DAO.Database
     Dim rst As DAO.Recordset
     Dim i As Integer
     Dim j As Integer
     Dim arr() As Variant
     Set db = CurrentDb
     Set rst = db.OpenRecordset("SELECT ArtikelID, Artikelname FROM tblArtikel", _
         dbOpenDynaset)
     arr = RecordsetInArrayMehrdimensional(rst)
     For i = LBound(arr, 1) To UBound(arr, 1)
         For j = LBound(arr, 2) To UBound(arr, 2)
             Debug.Print arr(i, j);
         Next j
         Debug.Print
     Next i
End Sub

Listing 5: Testprozedur zum Einlesen mehrdimensionaler Arrays

Das Ergebnis durchläuft die Prozedur dann in zwei verschachtelten For...Next-Schleifen. Bei der Ermittlung der Arraygrenzen der beiden Dimensionen verwenden wir natürlich eine andere Form der LBound- und UBound-Funktionen. Die untere Grenze der ersten Dimension ermitteln wir beispielsweise mit LBound(arr, 1), die der zweiten Dimension mit LBound(arr, 2).

Dies war die Leseprobe dieses Artikels.
Melden Sie sich an, um auf den vollständigen Artikel zuzugreifen.

Bitte geben Sie die Zeichenfolge in das nachfolgende Textfeld ein

Die mit einem * markierten Felder sind Pflichtfelder.

Ich habe die Datenschutzbestimmungen zur Kenntnis genommen.