I have a table called "Sales Tracker" I did an auto filter and got my results. now i want to transfer the visible fields to my array called soArray the first time i go thru the cells it works fine and i get the 4 fields i need into the array, however, after the first time i get a "Run-Time error'9': Subscript out of range" what am i doing wrong? any help or push would be appreciated, thank you below is my code
Sub getAllSO()
Dim wkb As Workbook
Dim wks As Worksheet
Set wkb = Workbooks("ScrubCentral.xlsm")
Set wks = wkb.Sheets("Sales Tracker")
Dim tbl As ListObject
Set tbl = wks.ListObjects("SalesTracker")
tbl.AutoFilter.ShowAllData
tbl.Range.AutoFilter field:=4, Criteria1:=">0"
Dim soArray() As Variant
Dim rngVisible As Range
Dim i As Long
Dim rCell As Range
With wks
With .AutoFilter.Range
Set rngVisible = .Offset(1, 0).Resize(.Rows.Count - 1, 1) _
.SpecialCells(xlCellTypeVisible)
End With
For Each rCell In rngVisible
i = i + 1
ReDim Preserve soArray(1 To i, 1 To 4)
soArray(i, 1) = rCell(i, 2)
soArray(i, 2) = rCell(i, 3)
soArray(i, 3) = rCell(i, 4)
soArray(i, 4) = rCell(i, 13)
Debug.Print soArray(i, 1), soArray(i, 2), soArray(i, 3), soArray(i, 4)
Next rCell
End With
End Sub
Preserve
keyword, you can resize only the last array dimension
.Microsoft documentation:
For Each rCell In rngVisible
is equivalent to For Each rCell In rngVisible.Cells
and does not extract data as your expected.
Moreover, a filtered table (ListObject
) often consists of non-contiguous ranges. To handle this properly, the script requires nested For Each
loops.
Sub getAllSO()
Dim wkb As Workbook
Dim wks As Worksheet
Set wkb = Workbooks("ScrubCentral.xlsm")
Set wks = wkb.Sheets("Sales Tracker")
Dim tbl As ListObject
' Set wks = ActiveSheet ' for debugging
Set tbl = wks.ListObjects("SalesTracker")
tbl.AutoFilter.ShowAllData
tbl.Range.AutoFilter field:=4, Criteria1:=">0"
Dim soArray() As Variant
Dim rngVisible As Range
Dim i As Long
With wks
With .AutoFilter.Range
Set rngVisible = tbl.DataBodyRange.SpecialCells(xlCellTypeVisible)
End With
Dim rArea As Range, rRow As Range
For Each rArea In rngVisible.Areas
For Each rRow In rArea.Rows
i = i + 1
ReDim Preserve soArray(1 To 4, 1 To i)
soArray(1, i) = rRow.Cells(2)
soArray(2, i) = rRow.Cells(3)
soArray(3, i) = rRow.Cells(4)
soArray(4, i) = rRow.Cells(13)
Next
Next
End With
' for testing
Sheets.Add
Range("A1").Resize(i, 4).Value = Application.Transpose(soArray)
End Sub
If the filtering criteria in your script are as straightforward as shown, an alternative approach could be loading the table into an array and applying the filtering logic using VBA.
Sub getAllSO2()
Dim wkb As Workbook
Dim wks As Worksheet
Set wkb = Workbooks("ScrubCentral.xlsm")
Set wks = wkb.Sheets("Sales Tracker")
Dim tbl As ListObject
' Set wks = ActiveSheet ' for debugging
Set tbl = wks.ListObjects("SalesTracker")
tbl.AutoFilter.ShowAllData
Dim loArray: loArray = tbl.DataBodyRange.Value
Dim soArray() As Variant
Dim i As Long, j As Long
Const KEY_COL = 4
For j = LBound(loArray) To UBound(loArray)
If loArray(j, KEY_COL) > 0 Then ' filtering table
i = i + 1
ReDim Preserve soArray(1 To 4, 1 To i)
soArray(1, i) = loArray(j, 2)
soArray(2, i) = loArray(j, 3)
soArray(3, i) = loArray(j, 4)
soArray(4, i) = loArray(j, 13)
End If
Next
' for testing
Sheets.Add
Range("A1").Resize(i, 4).Value = Application.Transpose(soArray)
End Sub
An alternative to repeated ReDim
statements is to pre-allocate sufficient array space to avoid frequent resizing.
Sub getAllSO3()
Dim wkb As Workbook
Dim wks As Worksheet
Set wkb = Workbooks("ScrubCentral.xlsm")
Set wks = wkb.Sheets("Sales Tracker")
Dim tbl As ListObject
' Set wks = ActiveSheet ' for debugging
Set tbl = wks.ListObjects("SalesTracker")
tbl.AutoFilter.ShowAllData
Dim loArray: loArray = tbl.DataBodyRange.Value
Dim soArray() As Variant
Redim soArray(1 To UBound(loArray), 1 to 4)
Dim i As Long, j As Long
Const KEY_COL = 4
For j = LBound(loArray) To UBound(loArray)
If loArray(j, KEY_COL) > 0 Then ' filtering table
i = i + 1
ReDim Preserve soArray(1 To 4, 1 To i)
soArray(i, 1) = loArray(j, 2)
soArray(i, 2) = loArray(j, 3)
soArray(i, 3) = loArray(j, 4)
soArray(i, 4) = loArray(j, 13)
End If
Next
' for testing
Sheets.Add
Range("A1").Resize(i, 4).Value = soArray
End Sub