Setting variable values dynamically using VBA - excel

I dont work with VBA much, I have a number of global integer variables, such as DFromRow1, DFromRow2, DFromRow3 up until DFromRow20. I want to set each of these in sequential order in this manner(This is just a very simple example to help you understand what I am trying to do) :
Dim Count as integer
Count = 0
Begin Loop(loop here for 20 times)
Count = Count + 1
DFromRow & Count = Count
End Loop
The idea here is that the global variables will be populated as such:
DFromRow1 = 1
DFromRow2 = 2
DFromRow3 = 3
... up until 20
However I get an error on the & :
Expected: expression
Is there a way to do this or am I being too ambitious with what I want ?
Thanks appreciate any help.

Instead of declaring 20 variables DFromRow you can use array
Something like this
Option Explicit
Public ArrDFromRow(20)
Sub Test()
Dim i As Long
For i = 1 To 20
ArrDFromRow(i) = i
Next i
For i = 1 To 20
Debug.Print ArrDFromRow(i)
Next i
End Sub

You can use an Array to store your values like this:
Dim DRowArray(1 to 20) as Long
Sub PopulateDFromRowArray()
Dim i as Integer
For i = LBound(DRowArray) to UBound(DRowArray)
DRowArray(i) = i
Next
End Sub
Or a Dictionary, albeit you need to set a VBA reference to Microsoft Scripting Runtime:
Dim DRowDict as Scripting.Dictionary
Sub PopulateDFromRowDictionary()
Dim i as Integer
Set DRowDict = New Scripting.Dictionary
For i = 1 To 20
DRowDict.Add "DFromRow" & i, i
Next
End Sub

Related

Is is possible to use a simple variable name to refer to a location in a VBA array

Is is possible to use a simple variable name to refer to a location in a VBA array?
I thought the location might be an object so I tried doing it kind of like this:
Sub ArrayRef()
Dim X As Integer
Dim ArrayWithQuiteALongName(1 To 3) As Integer
Dim A As Object
For X = 1 To 3
Set A = ArrayWithQuiteALongName(X)
A = X * 10
A = A * 10
Next X
Debug.Print ArrayWithQuiteALongName(1) = 100
Debug.Print ArrayWithQuiteALongName(2) = 200
Debug.Print ArrayWithQuiteALongName(3) = 300
End Sub
In the example I would expect a Debug.Print output of
TRUE
TRUE
TRUE
But this doesn't work and I can't seem to find any information on if it's possible

how to optimize for each loop in vba

I need to classify each row of a range accordingly with another range. The script works just fine. But it takes too much time even if it has no more than 300 rows. E.g. 298 rows take more than 2 minutes.
In order to achieve the classification, the script was built with a for each loop inside another one. All is done in the same worksheet called WSSeg. I tried to use all the good practices that I know of.
Option Explicit
Sub Input_Classification()
Application.ScreenUpdating = False
Application.EnableEvents = False
Dim TBLClassification As ListObject
Dim TBLReference As ListObject
Dim rClassificationCell As Range
Dim rClassification As Range
Dim rReferenceCell As Range
Dim rReference As Range
Set TBLClassification = WSSeg.ListObjects("TBClass")
Set rClassification = TBL.ListColumns(4).DataBodyRange
Set TBLReference = WSSeg.ListObjects("TBResumo")
Set rReference = TBL.ListColumns(4).DataBodyRange
For Each rClassificationCell In rClassification
For Each rReferenceCell In rReference
If rClassificationCell.Offset(0, -1).Value <= rReferenceCell.Value Then
rClassificationCell.Value = rReferenceCell.Value
End If
Next rReferenceCell
Next rClassificationCell
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
I expect the run time code to be shorter. I don't know if I have to use another logic system. Thanks in advance.
Tried to modify the code, it takes only 0.04 Secs with two tables of around 500 rows.
Tried to keep the replacement logic same as the original, But may please check the same, as i am little confused about the same. If find otherwise, please modify them to your need. Also Could not understand the what is TBL in cases with both the tables and assumed the obvious.
Option Explicit
Sub Input_Classification()
Dim WSSeg As Worksheet
Dim TBLClassification As ListObject
Dim TBLReference As ListObject
Dim rClassification As Range
Dim SrcArr As Variant, TrgArr As Variant, SrcCel As Variant
Dim i As Long, Tm As Double
Set WSSeg = ThisWorkbook.Sheets("Sheet1")
Tm = Timer
Set TBLClassification = WSSeg.ListObjects("TBClass")
Set rClassification = TBLClassification.ListColumns(3).DataBodyRange.Resize(TBLClassification.DataBodyRange.Rows.Count, 2)
TrgArr = rClassification.Value
Set TBLReference = WSSeg.ListObjects("TBResumo")
SrcArr = TBLReference.ListColumns(4).DataBodyRange.Value
For i = 1 To UBound(TrgArr, 1)
For Each SrcCel In SrcArr
If TrgArr(i, 1) <= SrcCel Then
TrgArr(i, 2) = SrcCel
End If
Next SrcCel
Next i
rClassification.Value = TrgArr
Debug.Print "Seconds taken " & Timer - Tm
End Sub
Since I personally don't prefer to keep calculations, event processing and screen updating off (in normal cases) i haven't added that standard lines. However you may use these standard techniques, depending on the working file condition.

Goal seek Run-time 1004 error when using application.run from another Workbook

I have a run-time error that I can't solve despite having searched deeply into many forum.
Here is the problem: I am using a Macro in a Model looking for a optimal allocation through a Goal-Seek function.
When I use it within that model (let's call it Model 1), the macro works perfectly.
However, i need to work in that model and in another one, to get data that will fill a table located in a 3rd excel file, which is then my "main file" (let's call it Model 3).
Thus, I need to call that macro located in Model 1 via an Application.run from Model 3.
And when I do so, I get a "Run-time error '1004': Reference isn't valid." which relates to the Goal-seek function that I use in Model 1.
Furthermore, if after that I come back to Model 1 and try to use the macro, I get the exact same error message while it was working before.
Here are my codes:
Model 3 (main):
Sub Test_Optim()
Dim JFMPath As String
Dim MacroPath As String
JFMPath = Sheets("Inputs").Range("D2")
MacroPath = Sheets("Inputs").Range("A3")
Workbooks.Open JFMPath
Application.Run (MacroPath)
End Sub
Model 1:
Option Explicit
Option Base 1
Sub Optimization_Alloc()
'Definitions
Dim i As Integer
Dim k As Integer
Dim IRR As Single
Dim IRRDelta As Single
Dim vIRR() As Single
Dim MinIRR As Single
Dim vPPA() As Single
Dim PPALevel As Single
Dim MinPPA As Single
Dim Position As Integer
Dim FlipYearIterations As Integer
Dim IterTF As Boolean
Dim IterStep As Single
Dim FlipYear As Integer
Dim OptFlipYear As Integer
Dim vFlipYear() As Integer
Dim xDistribution As Single
Dim OptxDistribution As Single
Dim vXDistribution() As Single
'enables goal-seek iterations, MaxIterations is the number you would wanna change
IterTF = Application.Iteration = True
IterStep = Application.MaxIterations
With Application
.Iteration = True
.MaxIterations = 500
.MaxChange = 0.0001
End With
FlipYearIterations = 10
ReDim vPPA(FlipYearIterations) As Single
ReDim vFlipYear(FlipYearIterations) As Integer
ReDim vXDistribution(FlipYearIterations) As Single
ReDim vIRR(FlipYearIterations) As Single
For i = 1 To FlipYearIterations
vFlipYear(i) = 2027 + i - 1
Next i
'Loops through different FlipYears. For every year, optimal allocation of cash/tax is calculated by goalseek.
For k = 1 To FlipYearIterations
Worksheets("As_Yr").Cells(345, 9) = vFlipYear(k) 'Optimal flip year
Worksheets("As_Yr").Cells(350, 9).GoalSeek Goal:=0, ChangingCell:=Worksheets("As_Yr").Cells(346, 9)
'Here is the Goalseek function from which I get the run-time error
xDistribution = Worksheets("As_Yr").Cells(346, 9)
PPALevel = Worksheets("Cockpit & As_Gen").Cells(48, 9)
vXDistribution(k) = xDistribution
vPPA(k) = PPALevel
vIRR(k) = Worksheets("As_Yr").Cells(348, 9)
Next k
'Determines optimal FlipYear
MinIRR = WorksheetFunction.Max(vIRR)
Position = WorksheetFunction.Match(MinIRR, vIRR, False)
OptFlipYear = vFlipYear(Position)
OptxDistribution = vXDistribution(Position)
'Prints optimal setting to Excel
Worksheets("As_Yr").Cells(345, 9) = OptFlipYear 'Optimal flip year
Worksheets("As_Yr").Cells(346, 9) = OptxDistribution 'Optimal CF distrib
'restores to the original goal-seek iterations setting
IterTF = Application.Iteration = True
IterStep = Application.MaxIterations
With Application
.MaxIterations = IterStep
.Iteration = IterTF
.MaxChange = 0.001
End With
End Sub
Is this something that one of you could help me with?
I guess it is a dummy mistake, but I can't figure that out.
Many thanks,
Alice

VBa Looping through RecordSets is too slow for my program

I have a RecordSet loop inside another RecordSet loop. It'd work well if it didn't take 45 secs for the .OpenRecordSet to run, and the table it'll open has 445k registers.
The reason for the inside loop is because I need to filter results obtained from another RecordSet, and then get these new results and compare.
Would it be better to use other methods, or other way? Is there another way to get specific data from a table(a faster way, of course)? Should I try multithreading?
Since people might need my code:
Private Sub btnGetQ_Click()
Dim tabEQ As DAO.Recordset: Dim tabT7 As DAO.Recordset: Dim tabPesqC As DAO.Recordset: Dim PesqCqdf As DAO.QueryDef
Dim index As Integer: Dim qtdL As Long: Dim qtdL2 As Long
Dim arrC() As String: Dim arrC2() As String: Dim arrC3() As String
Set tabEQ = dbC.OpenRecordset("EQuery", dbOpenSnapshot)
Set tabT7 = dbC.OpenRecordset("T7Query", dbOpenSnapshot)
If Not tabEQ.EOF Then
tabEQ.MoveFirst
qtdL = tabEQ.RecordCount - 1
ReDim arrC(qtdL): ReDim arrC2(qtdL)
If Not tabT7.EOF Then
tabT7.MoveFirst: index = 0
Do Until tabT7.EOF
arrC(index) = tabT7.Fields("CCO"): arrC2(index) = tabT7.Fields("CCE")
Set PesqCqdf = dbC.QueryDefs("pesqCCO")
PesqCqdf.Parameters("CCO") = arrC(index)
Set tabPesqC = PesqCqdf.OpenRecordset(dbOpenSnapshot)
qtdL2 = tabPesqConj.RecordCount - 1
If qtdL2 > 0 Then
ReDim arrC3(qtdL2)
Dim i As Integer
For i = 0 To UBound(arrC3)
arrC3(i) = tabPesqC.Fields("CCE")
tabPesqC.MoveNext
Next
End If
On Error GoTo ERROR_TabT7
index = index + 1: tabT7.MoveNext
Loop
End If
ERROR_TabT7:
Set tabT7 = Nothing
End If
If IsObject(tabEQ) Then Set tabEQ = Nothing
End Sub
I created tables linked with what i wanted :/

Can I Evaluate An Excel VB Constant That Is In String Format?

Is it possible to Evaluate a String which contains a valid Excel VB Constant's Name
to return that Constant's Value?
eg
Dim ConstantName as String
Dim ConstantValue as Long
ConstantName="xlValues"
ConstantValue= UnknownFunction(ConstantName)
'would set ConstantValue=-4163
Fun!
Option Explicit
Function getConstantValue(constStr As String) As Variant
Dim oMod As VBIDE.CodeModule
Dim i As Long, _
num As Long
Set oMod = ThisWorkbook.VBProject.VBComponents("Module1").CodeModule
For i = 1 To oMod.CountOfLines
If oMod.Lines(i, 1) = "Function tempGetConstValue() As Variant" Then
num = i + 1
Exit For
End If
Next i
oMod.InsertLines num, "tempGetConstValue = " & constStr
getConstantValue = Application.Run("tempGetConstValue")
oMod.DeleteLines num
End Function
Function tempGetConstValue() As Variant
End Function
All code must be in a module called Module1. That can be changed pretty simply by changing the text "Module1" in the routine.
You'll need to add a reference to Microsoft Visual Basic for Applications Extensibility x.x
There are a number of ways this could fail. Let me know if you have any problems with it :)
Instead of using constants, you could use a dictionary
Dim dict As Object
Sub InitialiseDict()
Set dict = CreateObject(Scripting.Dictionary)
dict("xlValues") = -4163
dict("const1") = value1
...
dict("constN") = valueN
End Sub
ConstValue = dict("xlValues")
Is using the string value necessary?
Dim anyConstant as Long
anyConstant = xlValues
msgbox anyConstant
Set anyConstant to any xl constant you please, they are all enumerated Long values.
The first solution offered is indeed much more fun however.

Resources