I have a macro executing formulas that are entered into cells, then applied to roughly 70,000 cells. The process takes more than 24 hours (it's still running). I need to find a way to speed up the process. My first thought is to populate the cells with the results of the formula instead of the formula itself, but I'm at a lost.
Currently, the macro scans three different worksheets to determine how many unique values there are. Then the formulas are applied for each unique value. Below is my code for one of the worksheets where the formulas are applied. I have some test code commented out that limited the rows to 40, but when I run all unique rows for this sample I have 56,136. For 40 rows, this still takes about 5 minutes.
'return to Summary and throw in formulas for each unique alarm per type
Range("A1").Select
Sheets("AlarmHistory-Summary").Select
Dim RowHeader As Long
Dim RowFirst As Long
Dim RowSecond As Long
Dim aUnqRowFirst As Long
Dim aUnqRowLast As Long
Dim dUnqRowFirst As Long
Dim dUnqRowLast As Long
Dim oUnqRowFirst As Long
Dim oUnqRowLast As Long
RowHeader = 1
RowFirst = 2
RowSecond = 3
dUnqRowFirst = RowFirst
dUnqRowLast = dUnqRowFirst + dCountUnique
aUnqRowFirst = dUnqRowLast + 1
aUnqRowLast = aUnqRowFirst + aCountUnique
oUnqRowFirst = aUnqRowLast + 1
oUnqRowLast = oUnqRowFirst + oCountUnique
Const ReturnType1 As String = "RETURN"
'Digital Point formulas
Range(dUnqRowFirst).Select
Set dSVA = Range("A" & dUnqRowFirst & ":A" & dUnqRowLast)
Set dSVB = Range("B" & dUnqRowFirst & ":B" & dUnqRowLast)
Set dSVC = Range("C" & dUnqRowFirst & ":C" & dUnqRowLast)
Set dSVD = Range("D" & dUnqRowFirst & ":D" & dUnqRowLast)
Set dSVE = Range("E" & dUnqRowFirst & ":E" & dUnqRowLast)
Set dSVF = Range("F" & dUnqRowFirst & ":F" & dUnqRowLast)
'Set dSVG = Range("G" & dUnqRowFirst & ":G" & dUnqRowLast)
Set dSVH = Range("H" & dUnqRowFirst & ":H" & dUnqRowLast)
'Set dSVA = Range("A" & dUnqRowFirst & ":A40")
'Set dSVB = Range("B" & dUnqRowFirst & ":B40")
'Set dSVC = Range("C" & dUnqRowFirst & ":C40")
'Set dSVD = Range("D" & dUnqRowFirst & ":D40")
'Set dSVE = Range("E" & dUnqRowFirst & ":E40")
'Set dSVF = Range("F" & dUnqRowFirst & ":F40")
'Set dSVG = Range("G" & dUnqRowFirst & ":G40")
'Set dSVH = Range("H" & dUnqRowFirst & ":H40")
dSVA.Formula = "=IFERROR(LOOKUP(2,1/(COUNTIF($A$" & RowHeader & ":A" & RowHeader & ",'AlarmHistory-Digital'!$D$" & dRowFirst & ":$D$" & dRowLast & ")=0),'AlarmHistory-Digital'!$D$" & dRowFirst & ":$D$" & dRowLast & "),"""")"
dSVB.Formula = "=IFERROR(LOOKUP(2,1/(COUNTIF($A$" & RowHeader & ":A" & RowHeader & ",'AlarmHistory-Digital'!$D$" & dRowFirst & ":$D$" & dRowLast & ")=0),'AlarmHistory-Digital'!$E$" & dRowFirst & ":$E$" & dRowLast & "),"""")"
dSVC.Formula = "=IF($A" & RowFirst & "="""","""",IFERROR(AVERAGEIFS('AlarmHistory-Digital'!$O:$O,'AlarmHistory-Digital'!$D:$D,$A" & RowFirst & ",'AlarmHistory-Digital'!$B:$B,""" & ReturnType1 & """),0))"
dSVD.Formula = "=IF($A" & RowFirst & "="""","""",IFERROR(MINIFS('AlarmHistory-Digital'!$O:$O,'AlarmHistory-Digital'!$D:$D,$A" & RowFirst & ",'AlarmHistory-Digital'!$B:$B,""" & ReturnType1 & """),0))"
dSVE.Formula = "=IF($A" & RowFirst & "="""","""",IFERROR(MAXIFS('AlarmHistory-Digital'!$O:$O,'AlarmHistory-Digital'!$D:$D,$A" & RowFirst & ",'AlarmHistory-Digital'!$B:$B,""" & ReturnType1 & """),0))"
dSVF.Formula = "=IF($A" & RowFirst & "="""","""",IFERROR(COUNTIFS('AlarmHistory-Digital'!$D:$D,$A" & RowFirst & ",'AlarmHistory-Digital'!$B:$B,""" & ReturnType1 & """),0))"
Range("G" & dUnqRowFirst).FormulaArray = "=IFERROR(LARGE(IF('AlarmHistory-Digital'!$D$" & dRowFirst & ":$D$" & dRowLast & "=$A" & RowFirst & ",'AlarmHistory-Digital'!$O$" & dRowFirst & ":$O$" & dRowLast & "),F" & RowFirst & "-ROUNDUP($F" & RowFirst & "*0.8,0)+1),"""")"
Range("G" & dUnqRowFirst).AutoFill Range("G" & dUnqRowFirst & ":G" & dUnqRowLast)
dSVH.Formula = "=COUNTIFS('AlarmHistory-Digital'!D:D,A" & RowFirst & ",'AlarmHistory-Digital'!O:O,""<""&G" & RowFirst & ")"
Range(aUnqRowFirst).Select
MsgBox "Digital Calculations Applied"
You can use advance filter, where A1:H1 are heading:
Range("Sheet1!A1:H1000").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range( _
"Sheet2!A1:H1"), Unique:=True
Could someone quickly tell me what's wrong with this syntax?
Sheets("Sheet1").Range("D" & i, "B" & i, "I" & i, "E" & i, "N" & i, "P" & i).Copy
This one is correct:
Sheets("Sheet1").Range("D" & i & ",B" & i & ",I" & i & ",E" & i & ",N" & i & ",P" & i).Copy
comma , should be inserted as string. I.e. you're trying to use (which is wrong):
Sheets("Sheet1").Range("D1","B1","I1","E1","N1","P1").Copy
but you should use:
Sheets("Sheet1").Range("D1,B1,I1,E1,N1,P1").Copy
Why is this code so slow? How to improve speed of excel. What's slowing down code. thanks a lot
Sub setVars()
Set ariba = Worksheets("Ariba Source")
Set kcm = Worksheets("KCM Commitment Report")
Set xdata = Worksheets("Data")
Set mani = Worksheets("Manually Investigate")
Set comm = Worksheets("Commitments")
Set commch = Worksheets("Commitment Changes")
Set test1 = Worksheets("Test") Set test2 = Worksheets("Test2")
End Sub
Call setVars
Dim AribaRows As Long
Dim DataRows As Long
Dim KCMRows As Long
Dim flag As Boolean, flag2 As Boolean, flag3 As Boolean, flag4 As Boolean
Dim l As Long
AribaRows = ariba.Cells(Rows.Count, 4).End(xlUp).Row DataRows = xdata.Cells(Rows.Count, 4).End(xlUp).Row KCMRows = kcm.Cells(Rows.Count, 1).End(xlUp).Row
With xdata For i = 2 To DataRows
.Range("U" & i).NumberFormat = "General"
.Range("O" & i).NumberFormat = "General"
.Range("P" & i).NumberFormat = "General"
.Range("O" & i).Formula = "=IF(MID(B" & i & ",1,2)=""WR"",B" & i & ",TRIM(MID(B" & i & ",1,7)))"
.Range("P" & i).Formula = "=O" & i & "&"".""&C" & i
.Range("Q" & i).Formula = "=IF((O" & i & "<>O" & i - 1 & "),1,IF(C" & i & "=C" & i - 1 & ",Q" & i - 1 & ",Q" & i - 1 & "+1))"
.Range("R" & i).Formula = "=IF(ISNUMBER(0 + MID(E" & i & ",23,3)),LEFT($E" & i & ",25),LEFT($E" & i & ",22))"
.Range("S" & i).Formula = "=IF(LEN(R" & i & ")=25,LEFT(RIGHT(E" & i & ", LEN(E" & i & ")-27),LEN(RIGHT(E" & i & ", LEN(E" & i & ")-27))-1),LEFT(RIGHT(E" & i & ", LEN(E" & i & ")-24),LEN(RIGHT(E" & i & ", LEN(E" & i & ")-24))-1))"
.Range("T" & i).Formula = "=LEFT(F" & i & ", LEN(F" & i & ")-11)"
.Range("U" & i).Formula = "=MID(RIGHT(F" & i & ",9),1,8)"
.Range("V" & i).Formula = "=G" & i
.Range("W" & i).FormulaArray = "=MAX(IF('Ariba Source'!$D$2:$D$" & AribaRows & "&'Ariba Source'!$L$2:$L$" & AribaRows & "&'Ariba Source'!$K$2:$J$" & AribaRows & "=E" & i & "&B" & i & "&D" & i & ",'Ariba Source'!$O$2:$O$" & AribaRows & "))"
.Range("X" & i).Formula = "=IF(ISERROR(DATEVALUE(MONTH(W" & i & ")&"" - ""&DAY(W" & i & ")&"" - ""&YEAR(W" & i & "))),W" & i & ",DATEVALUE(MONTH(W" & i & ")&"" - ""&DAY(W" & i & ")&"" - ""&YEAR(W" & i & ")))"
.Range("Y" & i).Formula = "=IF(INDEX('Ariba Source'!$P$2:$P$" & AribaRows & ",MATCH(E" & i & "&B" & i & "&D" & i & ",INDEX('Ariba Source'!$D$2:$D$" & AribaRows & "&'Ariba Source'!$L$2:$L$" & AribaRows & "&'Ariba Source'!$J$2:$J$" & AribaRows & ",),0))>0,(INDEX('Ariba Source'!$P$2:$P$" & AribaRows & ",MATCH(E" & i & "&B" & i & "&D" & i & ",INDEX('Ariba Source'!$D$2:$D$" & AribaRows & "&'Ariba Source'!$L$2:$L$" & AribaRows & "&'Ariba Source'!$J$2:$J$" & AribaRows & ",),0))/100*INDEX('Ariba Source'!$U$2:$U$" & AribaRows & ",MATCH(E" & i & "&B" & i & "&D" & i & ",INDEX('Ariba Source'!$D$2:$D$" & AribaRows & "&'Ariba Source'!$L$2:$L$" & AribaRows & "&'Ariba Source'!$J$2:$J$" & AribaRows & ",),0)))/SUMIFS('Ariba Source'!$U$2:$U$" & AribaRows & ",'Ariba Source'!$J$2:$J$" & AribaRows & ",D" & i & ",'Ariba Source'!$L$2:$L$" & AribaRows & ",B" & i & "),0)"
.Range("AA" & i).Formula = "=IF(LEFT(B" & i & ",2)=""WR"","""",IF(LEN(R" & i & ")=25,A" & i & "&"".256200.8190000"",A" & i & "&"".251000.1100""))"
.Range("Z" & i).Formula = "=IF(LEFT(B" & i & ",2)=""WR"",0,IF(J" & i & "=""KZT"",N" & i & "*0.08,N" & i & "*0.12))" Next i ' Up to here code works perfect
---------------------------------------#####################
For i = 2 To DataRows If DateValue(.Range("V" & i).Value) >= DateValue(MonthStart) And DateValue(.Range("V" & i).Value) <= DateValue(MonthEnd) Then
l = i - 1
flag2 = True
Do While .Range("A" & i).Value = .Range("A" & l).Value And .Range("O" & i).Value = .Range("O" & l).Value And l > 1
If .Range("R" & i).Value = .Range("R" & l).Value Then
If .Range("C" & i).Value = "03" Then
If .Range("C" & l).Value <> "00" And .Range("C" & l).Value <> "02" Then .Range("AB" & i).Value = "Manually Investigate"
Else
If CInt(.Range("C" & i).Value) > 3 And CInt(.Range("C" & i).Value) - CInt(.Range("C" & l).Value) > 1 Then .Range("AB" & i).Value = "Manually Investigate"
End If
flag2 = False
Exit Do
Else
If Not (.Range("R" & l).Value <> .Range("R" & l + 1).Value And .Range("C" & l).Value = .Range("C" & l + 1).Value And .Range("O" & l).Value = .Range("O" & l + 1).Value) Then
If .Range("C" & i).Value = "03" Then
If .Range("C" & i - 1).Value <> "00" And .Range("C" & i - 1).Value <> "02" Then .Range("AB" & i).Value = "Manually Investigate"
Else
If CInt(.Range("C" & i).Value) > 3 And CInt(.Range("C" & i).Value) - CInt(.Range("C" & i - 1).Value) > 1 Then .Range("AB" & i).Value = "Manually Investigate"
End If
flag2 = False
Exit Do
End If
End If
l = l - 1
Loop
If flag2 Then .Range("AB" & i).Formula = "=IF(AND(C" & i & "<>""00"",C" & i & "<>""02""),""Manually Investigate"","""")"
.Range("AE" & i).Formula = "=IF(AND(K" & i & "=K" & i - 1 & ",O" & i & "<>O" & i - 1 & ",R" & i & "=R" & i - 1 & "),""Manually Investigate"",IF(AND(K" & i & "=K" & i + 1 & ",O" & i & "<>O" & i + 1 & ",R" & i & "=R" & i + 1 & "),""Manually Investigate"",""""))"
If .Range("AE" & i).Value = "Manually Investigate" Then .Range("AE" & i - 1).Value = "Manually Investigate"
If .Range("AC" & i).Value <> "Manually Investigate" Then .Range("AC" & i).Formula = "=IF(AND(COUNTIF('KCM Commitment Report'!$C$2:$C$" & KCMRows & ",O" & i & ")>1,COUNTIFS('KCM Commitment Report'!$A$2:$A$" & KCMRows & ",A" & i & ",'KCM Commitment Report'!$C$2:$C$" & KCMRows & ",O" & i & ",'KCM Commitment Report'!$B$2:$B$" & KCMRows & ",""<>""&R" & i & ",'KCM Commitment Report'!$B$2:$B$" & KCMRows & ",""<>""&A" & i & "&"".256300.8190000"",'KCM Commitment Report'!$B$2:$B$" & KCMRows & ",""<>""&A" & i & "&"".256200.8190000"")>0),""Manually Investigate"","""")"
.Range("AH" & i).Formula = "=IF(AND(COUNTIF('KCM Commitment Report'!$C$2:$C$" & KCMRows & ",O" & i & ")>1,COUNTIFS('KCM Commitment Report'!$A$2:$A$" & KCMRows & ",""<>""&A" & i & ",'KCM Commitment Report'!$C$2:$C$" & KCMRows & ",O" & i & ")>0),""Manually Investigate"","""")"
.Range("AI" & i).Formula = "=IF(AND(J" & i & "<>""USD"",J" & i & "<>""KZT"",J" & i & "<>""EUR"",J" & i & "<>""GBP"",J" & i & "<>""RUB""),""Manually Investigate"","""")"
End If
.Range("AF" & i).Formula = "=IF(OR(I" & i & "=""Closed"",I" & i & "=""Cancelled"",I" & i & "=""Canceling""),""Manually Investigate"","""")"
If .Range("AB" & i).Value = "" And .Range("AC" & i).Value = "" And .Range("AD" & i).Value = "" And .Range("AF" & i).Value = "" Then .Range("AG" & i).Formula = "=IF(IFERROR(MATCH(O" & i & "&""Manually Investigate"",INDEX($O$2:$O$" & DataRows & "&$AC$2:$AC$" & DataRows & ",),0),0)<>0,""Manually Investigate"",IF(IFERROR(MATCH(O" & i & "&""Manually Investigate"",INDEX($O$2:$O$" & DataRows & "&$AD$2:$AD$" & DataRows & ",),0),0)<>0,""Manually Investigate"",IF(IFERROR(MATCH(O" & i & "&""Manually Investigate"",INDEX($O$2:$O$" & DataRows & "&$AB$2:$AB$" & DataRows & ",),0),0)<>0,""Manually Investigate"",IF(IFERROR(MATCH(O" & i & "&""Manually Investigate"",INDEX($O$2:$O$" & DataRows & "&$AF$2:$AF$" & DataRows & ",),0),0)<>0,""Manually Investigate"",""""))))"
.Range("AJ" & i).Formula = "=IF(AB" & i & "=""Manually Investigate"",""Manually Investigate"",IF(AC" & i & "=""Manually Investigate"",""Manually Investigate"",IF(AD" & i & "=""Manually Investigate"",""Manually Investigate"",IF(AE" & i & "=""Manually Investigate"",""Manually Investigate"",IF(AF" & i & "=""Manually Investigate"",""Manually Investigate"",IF(AG" & i & "=""Manually Investigate"",""Manually Investigate"",IF(AH" & i & "=""Manually Investigate"",""Manually Investigate"",IF(AI" & i & "=""Manually Investigate"",""Manually Investigate"",""""))))))))" Next i .Calculate Dim k As Long
Dim st
k = 2 flag = False For i = 2 To DataRows
st = ""
If .Range("AB" & i) = "Manually Investigate" Then st = st + "1,"
If .Range("AC" & i) = "Manually Investigate" Then st = st + "2,"
If .Range("AD" & i) = "Manually Investigate" Then st = st + "3,"
If .Range("AE" & i) = "Manually Investigate" Then st = st + "4,"
If .Range("AF" & i) = "Manually Investigate" Then st = st + "5,"
If .Range("AG" & i) = "Manually Investigate" Then st = st + "6,"
If .Range("AH" & i) = "Manually Investigate" Then st = st + "7,"
If .Range("AI" & i) = "Manually Investigate" Then st = st + "8,"
If .Range("AJ" & i) = "Manually Investigate" Then
st = VBA.Strings.Left(st, Len(st) - 1)
k = k + 1
flag = True
mani.Range("A" & k) = st
mani.Range("C" & k).Value = .Range("A" & i).Value
mani.Range("D" & k).Value = .Range("M" & i).Value
mani.Range("E" & k).Value = .Range("O" & i).Value
mani.Range("F" & k).Value = .Range("P" & i).Value
mani.Range("G" & k).Value = .Range("R" & i).Value
mani.Range("I" & k).Value = .Range("S" & i).Value
mani.Range("J" & k).Value = .Range("V" & i).Value
mani.Range("K" & k).Value = .Range("J" & i).Value
mani.Range("L" & k).Value = .Range("K" & i).Value
mani.Range("M" & k).Value = .Range("N" & i).Value
mani.Range("P" & k).Value = .Range("T" & i).Value
mani.Range("Q" & k).Value = .Range("U" & i).Value
mani.Range("R" & k).Value = .Range("I" & i).Value
mani.Range("S" & k).Value = .Range("H" & i).Value
mani.Range("T" & k).Value = .Range("B" & i).Value
mani.Range("U" & k).Value = .Range("D" & i).Value
mani.Range("V" & k).Value = .Range("C" & i).Value
mani.Range("W" & k).Value = .Range("E" & i).Value
mani.Range("X" & k).Value = .Range("F" & i).Value
End If Next i
i = 2 Do Until i >= DataRows
If VBA.Strings.Left(.Range("B" & i), 2) <> "WR" Then
.Range("A" & i).EntireRow.Copy
.Range("A" & i).Offset(1).EntireRow.Insert
.Range("R" & i).Offset(1).Formula = "=AA" & i
.Range("K" & i).Offset(1).Formula = "=Z" & i
.Range("N" & i).Offset(1).Formula = "=Z" & i
.Range("S" & i).Offset(1).Value = "Freight-All Road incl Rail"
.Range("L" & i).Offset(1).Value = ""
.Range("Z" & i).Offset(1).Value = ""
.Range("AA" & i).Offset(1).Value = ""
i = i + 1
DataRows = DataRows + 1
End If
i = i + 1
Loop
If flag = False Then
Call commitments
Else
mani.Activate
End If
End With
Have you tried to set
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
And after
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
I wonder how the formula calculations will work out when they have been modified by code... and your code is too contextual to what you are doing that I am not going to reverse engineer it to see what you are actually doing.
That little help is all I can provide.
use Option Explicit to make sure there's not a typo in the variables
additional speedup: to save you having to loop through all the values, we can use the fact that excel will adjust the formula as if you had copied it when changing a range.
e.g.
.Range("U2:U" & datarows).NumberFormat = "General"
......
.Range("O2:O" & datarows).Formula = "=IF(MID(B2,1,2)=""WR"",B2,TRIM(MID(B2,1,7)))"
.Range("P2:P" & datarows).Formula = "=O2&"".""&C2"
I have data in column A, C, E and G. I want column I to hold all of the data from these separated by semicolons, I have searched the web but all I find is how to replace line breaks with semicolons and that doesn't do it. Below are the 3 pieces of code I have attempted to work into it
Range("I" & i).Value = "=A" & i & Chr(59) & "&" & "C" & i & "&" & "E" & i & "&" & "G" & i
Range("I" & i).Value = "=A" & i & "&C" & i & "&E" & i & "&G" & i
Range("I" & i).Value = Range("A" & i).Value + ; + Range("C" & i).Value + ; + Range("E" & i).Value + ; + Range("G" & i).Value
The second line comes closest to what I want but when I add & ";" into it I get errors.
Any ideas thoroughly appreciated
SOLVED : This was solved by an answer below, I had managed my own fix which I will detail but the accepted answer is a cleaner, more efficient way
mystring = "=A" & i & "&" & Chr(34) & ";" & Chr(34) & "& C" & i & "&" & Chr(34) & ";" & Chr(34) & "& E" & i & "&" & Chr(34) & ";" & Chr(34) & "& G" & i
Range("I" & i).Value = mystring
You should use "&"";""".
In detail, you should use something like
"=A" & i & "&"";""" & "&C" & i
which result in
=A1&";"&C1
suppose i = 1.
=CONCATENATE(A1, ";", C1, ";", E1, ";", G1)
Using VBA
Range("A2").FORMULA = REPLACE("=CONCATENATE(A1, ';', C1, ';', E1, ';', G1)", "'", CHR(34))
I want to make a formula with a & inside it but VBA thinks its a concatenate symbol
""&"" does not work, are there any other tricks?
My formula:
Sheets("Elasticity").Cells(iRow, 38).Formula = "=SUMIFS(" & "All_Models!$W$2:$W$" & nrow & ",All_Models!$G$2:$G$" _ & nrow & ",Elasticity!L" & iRow & ",All_Models!$AL$2:$AL$" & nrow & ",Elasticity!AK" & iRow & _ ",All_Models!$B$2:$B$" & nrow & "," & "" <= "" & "&" & "ElasticityA" & iRow & ")"
I want to transform:
"" <= "" & "&" & "Elasticity!A" & iRow & ")"
into:
"<="&Elasticity!A2)
How about just this:
dim s as string
s = "my_complicated_formula" & "&" & "and_another_formula"
...All_Models!$B$2:$B$" & nrow & ",""<=""&" & "Elasticity!A" & iRow & ")"
s="foo" & Chr(38) & "bar"
Where chr(38) = &