VBA Access 2010 extracting array elements as individual dynamically named variables - arrays

I am working through an Access 2010 VBA script. I am pulling information from a temporary table that may have 1 to 10 records in it. I am using GetRows to build a two-dimensional array that looks like this, for example:
**0** **1**
8677229 1
10289183 2
11981680 3
13043481 4
I have tested the array function by debug print, and the array does contain values. I want to split out the array values dynamically into variables for later use. In this example, I would like the 0 column to produce 4 variables named Anum(0) through Anum(3), and the 1 column to produce 4 variables named Pay(0) through Pay(3). However, I keep getting a "Error 9, subscript out of range" where indicated below:
Dim db As Database
Dim rs As Recordset
Dim PayAcct As Variant
Set db = CurrentDb
Set rs = db.OpenRecordset("SELECT Anum, Pay FROM PayPerAcct")
Dim highval As Integer
Dim i As Integer
i = 0
While Not rs.EOF
PayAcct = rs.GetRows(10)
Wend
highval = UBound(PayAcct, 2)
Dim Anum() As Variant
Dim Pay() As Variant
For i = 0 To highval
'error occurs on the below line
Anum(i) = CStr(PayAcct(0, i))
Pay(i) = CStr(PayAcct(1, i))
Next i
When I manually define Anum and Pay variables and use the Cstr(PayAcct(1,0)) operation, it passes the expected value from the array to the variable, so I don't think that is the problem.
I suspect I am assigning Anum() and Pay() the wrong dimension, because I have seen similar example code in Excel VBA where defining those variables as Range works. I have tried defining Anum() and Pay() as Range (which doesn't work, because this is Access VBA), Variant, and Object.
Any thoughts or tips?
Edit -
The below ended up working, thanks for your help:
Dim Anum() As String
ReDim Anum(0 To highval)
Dim Pay() As String
ReDim Pay(0 To highval)

Dim Anum() As Variant
declares a dynamic array that hasn't any elements yet, so you can't assign values to it. It needs a ReDim to use it.
But since you already know how many elements you need, what you want is:
Dim Anum(0 To highval) As Variant
or if you know that you will only store strings in it,
Dim Anum(0 To highval) As String

Related

Passing data into SUMPRODUCT

I previously used the following code -
Dim HSArr(2 To 250) As Variant
Dim HSVal As Long
For HSVal = LBound(HSArr) To UBound(HSArr)
HSArr(HSVal) = Cells(HSVal, 1) & " " & Cells(HSVal, 2)
Next HSVal
It was an array that would concatenate column A and B, then the array would be output onto the worksheet in "P2:P250".
Sub SumData()
Const dFormula As String _
= "=IFERROR(SUMPRODUCT(--(P$2:P$250=I2),D$2:D$250,F$2:F$250),"""")"
With ThisWorkbook.Worksheets("Sheet1").Range("K2:K250")
.Formula = dFormula
.Value = .Value
End With
End Sub
This code does what I want to an extent but requires "P2:P250" to contain the array output, but I don't want to output anything onto the worksheet.
There's a piece of information that I do not understand here, how I can introduce those values from the array into the SUMPRODUCT (instead of "P2:P250"), even if its not by methods of array, as AFAIK I can't use that as a range without it being on the worksheet itself. Any idea?
Building an array with VBA then trying to use it with a formula in a worksheet without placing that information into a worksheet generally wouldn't work, however here you can use the source data in the formula instead:
=IFERROR(SUMPRODUCT(--(A$2:A$250&" "&B$2:B$250=I2),D$2:D$250,F$2:F$250),"""")

Populate an array without a loop

I am trying to avoid the use of loops for populating arrays since they take a lot of time when managing a lot of data.
Apparently as well, that is possible and easy in VBA but often results in problems.
Here is the code:
sub populate()
'put the whole column in an array
Dim AppArray() As Variant
Dim AppRange As Range
'calculate the last row of the column 1 of sheets
Dim LstRow As Integer
LstRow = Sheets("whole").Cells(Sheets("whole").Rows.Count, "A").End(xlUp).row
'here I calculate the range that I want to pass to the array
Set AppRange = Sheets("whole").Range(Cells(1, 1), Cells(LstRow, 1))
MsgBox ("apprange " & AppRange.Address)
'i dont know if I need to redim or not
ReDim AppArray(1 To LstRow)
'here comes the point. populate the array with the values of the range
AppArray = AppRange.Value
End Sub
This does not work. I also tried application.tranpose(AppRange.Value).
I used:
For i = 1 To LstRow
Debug.Print AppArray(i)
Next
and an error appears, so somehow there is no AppArray(1).
I would be very happy if you can comment on that. More than just arranging the code suggest even other pages (links) to populate arrays with values of ranges when these ranges are not known in advance.
If the case is that looping is very time consuming and that arrays can be populated straight away, I don't understand why 99% of the pages referring to arrays use a loop (or nested loop) to populate an array.
I found the answer.
dim myRange as range
dim myArray() as variant
myRange = range(cells(2,3),cells(10,15))
redeem myArray(1 to 20,1 to 20)
myArray=myRange
It's always much faster to work with variables and arrays than with cells values.

Excel VBA: adding a row to a variant array in one line

I´d like to add a row to a variant array:
Dim arrMod As Variant
arrMod(numberOfRow) = Array(myValue1, myValue2, myvalue3)
The execution of this code results into an exception: Error 13: type mismatch
How can I do it without iterating each column?
Thanks,
Regards
Your variable arrMod is not an array. You need to define it in VBA as an array using parenthesis:
Dim arrMod(0) As Variant
Obviously replace 0 with the maximum number of rows you have, or resize dynamically using redim preserve.
Do you need something like this:
Dim arrMod()
For i = 1 To 5
ReDim Preserve arrMod(i)
arrMod(i) = i
MsgBox Join(arrMod, vbCrLf)
Next i

Declaring a dynamic array not working as expected

RsProxyList.Open objDBCommand,,1,1
dim recCount:recCount = RsProxyList.RecordCount
Dim output(recCount,2)
I get an error because recCount is of wrong type. I have tried to convert it to Int but that does not work either. The following works fine:
RsProxyList.Open objDBCommand,,1,1
dim recCount:recCount = RsProxyList.RecordCount
Dim output(3,2)
How do I convert recCount to get this array declaration to work?
You need to first declare your Array as dynamic then use ReDim to set the first dimension dynamically, like this;
Dim output() 'Declare a "Dynamic Array"
ReDim output(recCount, 2) 'Set dynamic first dimension.
By specifying the dimensions like this;
Dim output(10, 2) 'Declare a "Fixed Array"
you tell VBScript to build a fixed array which does not accept variables as dimension declarations.
Dim output() versus Dim output
There seems to be some argument as to using
Dim output()
versus
Dim output
#Bond in the comments below came up with the most convincing one in my opinion for using Dim output().
Because VBScript stores all variables as Variant data type declaring an Array using Dim output is just like declaring any other variable, whereas Dim output() creates an Array (0 sized array but an array nonetheless), this means there is one significant difference as far as the VBScript Runtime is concerned, Dim output() is an Array.
What does this matter?, well it matters because functions like IsArray() will still detect the variable as an Array where as "arrays" declared using Dim output will return False.
Useful Links
#DougGlancy's answer to Redim without Dim? (vba but still relevant).
VBScript Reference - Dim Statement
VBScript Reference - VBScript Variables (specifically Array Variables sub heading).

Array in excel vba

I want to have an array list in vba, hence I have a variant declared in excel vba like:
Dim Students(10) as variant
Now I want to store numbers in Students list. the numbers are not continuous. Sometime like:
Students(2,7,14,54,33,45,55,59,62,66,69)
How can I do this in vba? also how can I access the list items?
Students must be declared as a dynamic array. That is, an array whose bounds can be changed. Dim Students(10) gives an array whose bounds cannot be changed and cannot be loaded from an array.
Dim Students() As Variant
To load Students:
Students = Array(2,7,14,54,33,45,55,59,62,66,69)
To access the elements:
Dim Inx As Long
For Inx = LBound(Students) to UBound(Students)
Debug.Print Students(Inx)
Next
LBound (Lower bound) and UBound mean that the for loop adjusts to the actual number of elements in Students.
This is too complex for you right now, and you'll probably never run into a situation where you'll need this, but:
I use the following method for forming more memory-efficient arrays (because Variant uses the most memory of any variable type) while still having the convenience of declaring the array contents in one line. To follow your example:
Dim Students() As Long
Dim Array2() As String
Array2() = Split("2,7,14,54,33,45,55,59,62,66,69", ",")
ReDim Array1(0) As Long
For Loop1 = LBound(Array2()) To UBound(Array2())
ReDim Preserve Array1(0 To (UBound(Array1) + 1)) As String
Array1(Loop1) = Array2(Loop1)
Next Loop1
ReDim Preserve Array1(0 To (UBound(Array1) - 1)) As Long
Erase Array2
An example of accessing it would be something like:
For Loop1 = LBound(Students) to UBound(Students)
Msgbox Students(Loop1)
Next Loop1
I learned this from here: http://www.vbforums.com/showthread.php?669265-RESOLVED-VBA-Excel-Assigning-values-to-array-in-a-single-line&p=4116778&viewfull=1#post4116778
You can add values to an Array like this...
For i = 1 to 10
Students(i) = i
Next i
Or like this
Students = Array(2,7,14,54,33,45,55,59,62,66,69)
Then you can access the values in the same manor. Note if you use the second option you'll need to declare it as follows:
Dim Students() As Variant
Well,
That depends on how you would supply the values for the array, would you get the values from Worksheet.Range or from TextBox or ListBox , But basically the code would be something like that :
Dim students(10) as Integer
Dim Carrier as Integer
For i = LBound(students) To UBound(Students)
'some code to get the values you want to from whatever is your source
'then assign the value to Carrier
students(i)=Carrier
Next i
It is not good practice to dim an array as Variant when you certainly know that you are going to use integers only, as it will eat alot of memory that is not needed in the first place.
You also should be aware of the bounds of the numbers that are going to be assigned, if it exceeds the Integer limit then you should use Double or Float.
This is my first participation in the site,Cheers.

Resources