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 RecordsetInArrayEindimensional 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.
Bild 1: Automatische Ergänzung eines FeldnamensAlso 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.