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).
Related
Why am I unable to set the size of an array based on a variable? What's the best way around this?
Dim NumberOfZombies as integer
NumberOfZombies = 20000
Dim Zombies(NumberOfZombies) as New Zombie
You can use a dynamic array when you don't know the number of values it will contain until run-time:
Dim Zombies() As Integer
ReDim Zombies(NumberOfZombies)
Or you could do everything with one statement if you're creating an array that's local to a procedure:
ReDim Zombies(NumberOfZombies) As Integer
Fixed-size arrays require the number of elements contained to be known at compile-time. This is why you can't use a variable to set the size of the array—by definition, the values of a variable are variable and only known at run-time.
You could use a constant if you knew the value of the variable was not going to change:
Const NumberOfZombies = 2000
but there's no way to cast between constants and variables. They have distinctly different meanings.
You have to use the ReDim statement to dynamically size arrays.
Public Sub Test()
Dim NumberOfZombies As Integer
NumberOfZombies = 20000
Dim Zombies() As New Zombie
ReDim Zombies(NumberOfZombies)
End Sub
This can seem strange when you already know the size of your array, but there you go!
You can also look into using the Collection Object. This usually works better than an array for custom objects, since it dynamically sizes and has methods for:
Add
Count
Remove
Item(index)
Plus its normally easier to loop through a collection too since you can use the for...each structure very easily with a collection.
You need to use a constant.
CONST NumberOfZombies = 20000
Dim Zombies(NumberOfZombies) As Zombies
or if you want to use a variable you have to do it this way:
Dim NumberOfZombies As Integer
NumberOfZombies = 20000
Dim Zombies() As Zombies
ReDim Zombies(NumberOfZombies)
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
Say I have a path in Range("A1") that looks like this:
/data/apps/server/
I would like to get the three elements into a variable. I've thought doing a Split() by the separator / I would get the full array:
Dim myElements()
myElements = Split(Range("A1").Value,"/")
'>>> EXPECTED: myElements is [data, apps, servers]
but I actually get a Type mismatch error on the line myElements = Split(Range("A1").Value,"/"). What does the Split function return? Does it actually return the array or it rather gives read-only access?
I would just like to get the array of the Split method without having to loop through them and build my own array, if possible of course.
Change Dim elements() to Dim elements As Variant
You need to declare it as a Variant.
Explanation:
The data in Excel cell can be anything. So use a Variant. In cases like below, you know it is a String so declare it like a String
Sub Sample()
Dim myElements() As String
Dim myString As String
myString = "aaa/bbb/ccc"
myElements = Split(myString, "/")
Debug.Print myElements(0)
Debug.Print myElements(1)
Debug.Print myElements(2)
End Sub
Split returns a String Array. You may want to see This
Edit: I have a feeling that I may confuse someone with my explanation so let me explain it a bit more.
Dim myElements() means "Declare myElements as array of Variants".
Split returns an array of Strings. Hence, the mismatch.
You can do either Dim myElements or Dim myElements as Variant or Dim myElements() as String to resolve the problem.
Here is why each one of these works:
Dim myElements and Dim myElements as Variant
Both of these means that you declare myElements as Variant. Variants are special types, which can accept anything. As such, they can accept array of strings easily. However, variants have large memory overheads and should be avoided wherever possible.
Dim myElements() as String
This means that you declare myElements as array of strings. Since this is the same type as what is returned by the Split function, it is accepted.
Ideally, if you know the return type of a function, you should specify the correct type for your variables.
So in this case, Dim myElements() as String which is the same type returned from the Split funcition.
Assigning a Range to an Array is pretty simple. Still, I found a case in which VBA behaved unexpectedly. I could not find an answer why that is and so I hope someone can explain to me, why it is not working.
Task: Assign a Range (from an open Workbook) to an Array
Working Code
Dim vrtTabOEen () as Variant
Dim rngTabOEen as Range
With ThisWorkbook.Worksheets(Name_AB_Tab_Def_OEen)
Set rngTabOEen = .Range(Name_Tab_Def_OEen)
vrtTabOEen = rngTabOEen
End With
Non-Working Code
Dim vrtTabOEen () as Variant
With ThisWorkbook.Worksheets(Name_AB_Tab_Def_OEen)
vrtTabOEen = .Range(Name_Tab_Def_OEen)
End With
Using the non-working code, I'll get error 13: Type mismatch.
Question
Why do I have to assign the target range to a variable of type 'range' before creating an array out of it?
You have too many levels of indirection for the implicit coercion from Variant to Variant array to work, due to the fact that Worksheets returns a generic Object and you didn't specify the value property, which you should always do. Either:
Dim vrtTabOEen () as Variant
With ThisWorkbook.Worksheets(Name_AB_Tab_Def_OEen)
vrtTabOEen = .Range(Name_Tab_Def_OEen).Value
End With
or:
Dim vrtTabOEen as Variant
With ThisWorkbook.Worksheets(Name_AB_Tab_Def_OEen)
vrtTabOEen = .Range(Name_Tab_Def_OEen)
End With
should work.
Why am I unable to set the size of an array based on a variable? What's the best way around this?
Dim NumberOfZombies as integer
NumberOfZombies = 20000
Dim Zombies(NumberOfZombies) as New Zombie
You can use a dynamic array when you don't know the number of values it will contain until run-time:
Dim Zombies() As Integer
ReDim Zombies(NumberOfZombies)
Or you could do everything with one statement if you're creating an array that's local to a procedure:
ReDim Zombies(NumberOfZombies) As Integer
Fixed-size arrays require the number of elements contained to be known at compile-time. This is why you can't use a variable to set the size of the array—by definition, the values of a variable are variable and only known at run-time.
You could use a constant if you knew the value of the variable was not going to change:
Const NumberOfZombies = 2000
but there's no way to cast between constants and variables. They have distinctly different meanings.
You have to use the ReDim statement to dynamically size arrays.
Public Sub Test()
Dim NumberOfZombies As Integer
NumberOfZombies = 20000
Dim Zombies() As New Zombie
ReDim Zombies(NumberOfZombies)
End Sub
This can seem strange when you already know the size of your array, but there you go!
You can also look into using the Collection Object. This usually works better than an array for custom objects, since it dynamically sizes and has methods for:
Add
Count
Remove
Item(index)
Plus its normally easier to loop through a collection too since you can use the for...each structure very easily with a collection.
You need to use a constant.
CONST NumberOfZombies = 20000
Dim Zombies(NumberOfZombies) As Zombies
or if you want to use a variable you have to do it this way:
Dim NumberOfZombies As Integer
NumberOfZombies = 20000
Dim Zombies() As Zombies
ReDim Zombies(NumberOfZombies)