I'm trying to create a macro for a Personal Budget worksheet, where there is a cell with tedious work.
Using the "Record Macro" button I traced the coding behind the operation I made in the cell, which is the following:
Sub calculo_otherex()
' calculo_otherex Macro
' Cálculo de otros gastos con tarjeta.
'
ActiveCell.FormulaR1C1 = _
"=Extractos!R[-89]C[-2]-('Home Expenses'!R[-105]C+'Home Expenses'!R[-60]C+'Home Expenses'!R[-16]C+Health!R[-105]C+Health!R[-67]C+Health!R[-29]C+Gifts!R[-99]C+'Daily Living'!R[-87]C+'Daily Living'!R[-29]C+'Daily Living'!R[20]C+'Daily Living'!R[59]C+'Daily Living'!R[102]C+Entertainment!R[-105]C+Entertainment!R[-67]C+Entertainment!R[-29]C+Entertainment!R[9]C+Transportation!R[-105]C)"
Range("H129").Select
End Sub
As you can see, in the formula I refer to other sheets, and to specific cells which reflect a result of a certain month (in this case July) and a specific subset (charges to a credit card).
What I want to do is insert a loop so this procedure repeats for all the months, but the problem is that the data in the sheet "Extractos" appears every 7th cell to the right from "Extractos!R[-89]C[-2]", as the other data in the formula appears in the next column.
How could I solve this??
Thank you very much.
Give the following a try... It's hard to read R1C1, so I changed it up a bit and you'll need to replace all my "A1" references to the first month's cell reference. Also, the for loop will only loop 12 times - 12 months in a year. You can manually change this if you'd like. Lastly, the formula will be written in the activecell then the following formulas will be written in the next cell/column to the right.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'instead of using R1C1, use ranges with offsets - it's much easier to read :) ''
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'I used "A1" as a placeholder. Replace this with the actual cell reference for the first month
'The first loop will use the "A1" range. Then, the 2nd and following loops will move over 1 or 7 columns
'i = move over 1 column
'x = move over 7 columns
For i = 0 To 11 'this will loop through 12 times 0-11
ActiveCell.Offset(0, i).Formula = _
"=Extractos!" & Range("A1").Offset(0, x).Address _
& "-('Home Expenses'!" & Range("A1").Offset(0, i).Address _
& "+'Home Expenses'!" & Range("A1").Offset(0, i).Address _
& "+'Home Expenses'!" & Range("A1").Offset(0, i).Address _
& "+Health!" & Range("A1").Offset(0, i).Address _
& "+Health!" & Range("A1").Offset(0, i).Address _
& "+Health!" & Range("A1").Offset(0, i).Address _
& "+Gifts!" & Range("A1").Offset(0, i).Address _
& "+'Daily Living'!" & Range("A1").Offset(0, i).Address _
& "+'Daily Living'!" & Range("A1").Offset(0, i).Address _
& "+'Daily Living'!" & Range("A1").Offset(0, i).Address _
& "+'Daily Living'!" & Range("A1").Offset(0, i).Address _
& "+'Daily Living'!" & Range("A1").Offset(0, i).Address _
& "+Entertainment!" & Range("A1").Offset(0, i).Address _
& "+Entertainment!" & Range("A1").Offset(0, i).Address _
& "+Entertainment!" & Range("A1").Offset(0, i).Address _
& "+Entertainment!" & Range("A1").Offset(0, i).Address _
& "+Transportation!" & Range("A1").Offset(0, i).Address & ")"
'add 7 to x variable
x = x + 7
'loop and add 1 to i
Next i
'macro done, select H129
Range("H129").Select
Related
Good morning all,
I have a problem with vba translating formulas into excel:
I've got this code:
'Tramos para calcular el total, mañana, tarde y noche
TramoIni = Array(4, 20, 36, 4)
TramoFin = Array(51, 35, 51, 19)
'Formulas
FormulaTramo = _
Array("=SUMIFS('Mapa Turnos'!C[4],'Mapa Turnos'!C1,RC1,'Mapa Turnos'!C3,RC2)/30", _
"=R[-1]C*(1-SUM(R[5]C:R[8]C))", _
"=IFERROR(IF(IFERROR((R[13]C*R[-1]C*1800)/R[3]C,0)/R[2]C>1,1," _
& "IFERROR((R[13]C*R[-1]C*1800)/R[3]C,0)/R[2]C),0)", _
"=sla(IF(R[-2]C=0,0,IF(R[-2]C<1,1,R[-2]C)),INDIRECT(ADDRESS(MATCH(RC2,Objetivos!C2,0),4," _
& ",,""Objetivos"")),R[1]C,R[2]C)", _
"=IF(AND(R[-7]C>0,R[-11]C=0),""SI"",""NO"")", _
"=1", _
"=1", _
"=SUM(RC1:RC2)", _
"=R[-11]C-R[-2]C", _
"=CallCapacity(R[-12]C,INDIRECT(ADDRESS(MATCH(RC2,Objetivos!C2,0),3," _
& ",,""Objetivos"")),INDIRECT(ADDRESS(MATCH(RC2,Objetivos!C2,0),4,,,""Objetivos"")),R[-8]C)", _
"=IF(R[-1]C>R[-10]C,R[-10]C,R[-1]C)", "=Utilisation(R[-14]C,R[-11]C,R[-10]C)")
LastRow = ws.Range("A100000").End(xlUp).Row
Col = ws.Range("XDF4").End(xlToLeft).Column
ColTotal = ws.Cells.Find("Total").Column
ColF = ColTotal - 1
ColMañana = ws.Cells.Find("Mañana").Column
ColTarde = ws.Cells.Find("Tarde").Column
ColNoche = ws.Cells.Find("Noche").Column
For i = 1 To UBound(KPI)
ws.Range(ws.Cells(4, 1), ws.Cells(LastRow, Col)).AutoFilter Field:=3, Criteria1:=KPI(i)
If KPI(i) <> "5.Pronóstico" And KPI(i) <> "92.Requeridos" Then
With ws.Range(ws.Cells(5, 4), ws.Cells(LastRow, ColF)).SpecialCells(xlCellTypeVisible)
.FormulaR1C1 = "'" & FormulaTramo(i - 1)
End With
End If
For x = 0 To UBound(TramoIni)
'Formulas total, mañana, tarde y noche
FormulaTotal = _
Array("=SUM(RC" & TramoIni(x) & ":RC" & TramoFin(x) & ")/2", _
"=SUM(RC" & TramoIni(x) & ":RC" & TramoFin(x) & ")/2", _
"=IFERROR(IF(SUMPRODUCT(RC" & TramoIni(x) & ":RC" & TramoFin(x) & ",R[2]C" & TramoIni(x) & _
":R[2]C" & TramoFin(x) & ")/R[2]C>1,1,SUMPRODUCT(RC" & TramoIni(x) & _
":RC" & TramoFin(x) & ",R[2]C" & TramoIni(x) & ":R[2]C" & TramoFin(x) & ")/R[2]C),0)", _
"=IFERROR(SUMPRODUCT(RC" & TramoIni(x) & ":RC" & TramoFin(x) & ",R[1]C" & TramoIni(x) & _
":R[1]C" & TramoFin(x) & ")/R[1]C,0)", _
"=SUM(RC" & TramoIni(x) & ":RC" & TramoFin(x) & ")", _
"=SUM(RC" & TramoIni(x) & ":RC" & TramoFin(x) & ")/2", _
"=IF(COUNTIF(RC" & TramoIni(x) & ":RC" & TramoFin(x) & ",""SI"")>0,""SI"",""NO"")", _
"=IFERROR(SUM(RC" & TramoIni(x) & ":RC" & TramoFin(x) & ")/2,0)", _
"=SUM(RC" & TramoIni(x) & ":RC" & TramoFin(x) & ")", _
"=IF(R[-2]C>R[-10]C,R[-10]C,R[-2]C)", _
"=IFERROR(IF(SUMPRODUCT(RC" & TramoIni(x) & ":RC" & TramoFin(x) & ",R[-14]C" & _
TramoIni(x) & ":R[-14]C" & TramoFin(x) & ")/R[-14]C>1,1,SUMPRODUCT(RC" & _
TramoIni(x) & ":RC" & TramoFin(x) & ",R[-14]C" & TramoIni(x) & ":R[-14]C" & _
TramoFin(x) & ")/R[-14]C),0)")
With ws.Range(ws.Cells(5, TramoFin(0) + x + 1), ws.Cells(LastRow, TramoFin(0) + x + 1)). _
SpecialCells(xlCellTypeVisible)
.FormulaR1C1 = "'" & FormulaTotal(i - 1)
End With
Next x
Next i
ws.Rows(4).AutoFilter
x = ws.Range("A100000").End(xlUp).Row
i = ws.Range("XDF4").End(xlToLeft).Column
ws.Range(ws.Cells(5, 4), ws.Cells(x, i)).Value = ws.Range(ws.Cells(5, 4), ws.Cells(x, i)).Value
This is just some arrays containing formulas and the column where they should start taking values.
The thing is that the if, countif and sum aren't taking the cells references when going to excel:
As you can see above every formula has the same cell reference, the one that vba has.
But later on when we convert it to excel (last line of code):
As you can see sumproducts worked well, but the rest are taking literally the column RC and the row which was supposed to be the column reference on VBA.
Any thoughts what could be doing this? I need to work like this because this worksheet can have up to 7k rows and 50+ columns with formulas in like the 80% of them so introducing the formulas in every loop would take ages, instead I'm doing this so they all recalculate at the same time.
This way still takes ages to calculate and I don't know if there is a more efficient way to input so many formulas which include erlangs and custom functions.
Any help would be appreciated! Thanks!
MCVE of the problem in question:
Range("A1").FormulaR1C1 = "'" & "=SUM(RC20:RC25)"
Range("A1").Value = Range("A1").Value
Formula in RC-notation is assigned to the Value property. Excel tries to recognize the formula type. There are only absolute references in this formula, so it looks like valid A1-notation relative formula.
Some of the formulas containing relative references (with square brackets) were correctly recognized as RC notation - because those would not be valid A1 formulas.
To solve the problem, array with formulas needs to be assigned to FormulaR1C1 property:
ws.Range(ws.Cells(5, 4), ws.Cells(x, i)).FormulaR1C1 = ws.Range(ws.Cells(5, 4), ws.Cells(x, i)).Value
Much better way to avoid long calculations during code execution is to disable automatic calculation:
Application.Calculation = xlCalculationManual
'all code here
Application.Calculation = xlCalculationAutomatic
Lastrow = ActiveSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Row
For i = 3 To Lastrow
Sheets("sample").Range("AM1000000").End(xlUp).Offset(1, 0).Select
Selection.FormulaArray = _
"=IF(ISNUMBER(MATCH(1," & Chr(10) & " (order!R2C15:R1000000C15=RC[-24])*" & Chr(10) & " (order!R2C7:R1000000C7=RC[-32])*" & Chr(10) & " (order!R2C24:R1000000C24=RC[-15])," & Chr(10) & " 0)), ""pass"",""review"")"
Next i
Columns("AM:AM").Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
I am using match formula inside of for loop, but it is taking too much time. Is there any way to optimize this code to make it go faster?
Thank you!
There are quite a few improvements you could make, a couple of main ones are:
1) Reading and writing to cells on a worksheet is very slow, as are string manipulations. Instead work out the result first then write it to the sheet rather than write a formula to the cell. Better yet, store the results in an array and write them all out at the end (but that is beyond the scope of this question, you can search about arrays online). You can use application.worksheetfunction to recreate your existing formulas in VBA, or you might consider creating your own function to do it.
2) Avoid selecting cells, again - a very slow operation. Instead use your for loop with the Cells reference to specify the affected cell:
For i = 3 To Lastrow
Sheets("sample").cells(i, 39).FormulaArray = _
"=IF(ISNUMBER(MATCH(1," & Chr(10) & " (order!R2C15:R1000000C15=RC[-24])*" & Chr(10) & " (order!R2C7:R1000000C7=RC[-32])*" & Chr(10) & " (order!R2C24:R1000000C24=RC[-15])," & Chr(10) & " 0)), ""pass"",""review"")"
Next i
The Cells syntax is (row, column). Here i is the row number, 39 is column AM.
By lessening the reference range in the array formulas we can speed it up.
Also removing the clipboard will also speed it up:
lastrow = ActiveSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Row
For i = 3 To lastrow
With WorksSheets("sample").Range("AM" & i)
.FormulaArray = _
"=IF(ISNUMBER(MATCH(1," & Chr(10) & " (order!R2C15:R" & lastrow & "C15=RC[-24])*" & Chr(10) & " (order!R2C7:R" & lastrow & "C7=RC[-32])*" & Chr(10) & " (order!R2C24:R" & lastrow & "C24=RC[-15])," & Chr(10) & " 0)), ""pass"",""review"")"
.Value = .Value
End With
Please could you tell me what is wrong with my second last SUMIFS formula where I use " < " &$F$1. All that is returned is FALSE in all the cells. The last SUMIFS without the < works fine.
Sub SumGroups()
Worksheets("Database").Activate
Dim lastCode, lastFiltCode As Integer
Dim Formula As String
'Determine Last Row in Column O (Unfiltered Codes)
lastCode = Range("O" & Rows.Count).End(xlUp).Row
'Filter Unique Codes into Column A Sheet2
Range("O1:O" & lastCode).AdvancedFilter Action:=xlFilterCopy, _
CopyToRange:=Sheet2.Range("A1"), Unique:=True
'Determine last Row in Column A (Filtered Codes)
Worksheets("Sheet2").Activate
lastFiltCode = Sheet2.Range("A" & Rows.Count).End(xlUp).Row
'Place SUMIF Formulas in Columns Sheet2
Worksheets("Sheet2").Range("B2:B" & lastFiltCode).Formula = _
"=SUMIFS(Database!$M$2:$M$" & lastCode & ",Database!$O$2:$O$" & lastCode & ",A2)"
Worksheets("Sheet2").Range("D2:D" & lastFiltCode).Formula = _
"=SUMIFS(Database!$M$2:$M$" & lastCode & ",Database!$O$2:$O$" & lastCode & ",A2,Database!$I$2:$I$" & lastCode & "," < " &$F$1)"
Worksheets("Sheet2").Range("F2:F" & lastFiltCode).Formula = _
"=SUMIFS(Database!$M$2:$M$" & lastCode & ",Database!$O$2:$O$" & lastCode & ",A2,Database!$I$2:$I$" & lastCode & ",$F$1)"
End Sub
Just to clarify why the other answers work:
SumIfs (as well as various other Excel functions requiring string operators (such as CountIf) expect that logical operators and their following statements be expressed as a string. I.e. should be enclosed in speech marks e.g. "myString".
Since a formula is also a string e.g. ActiveCell.Formula = "=If(A1=3, 1, 0)" the compiler gets confused about which set of quotation marks denotes the string. So for example this will not work: ActiveCell.Formula = "=If(A1=3, "Yes", "No")".
Technically the way to deal with this is to enclose the required quotation mark in quotation marks of it own; """ myValue """.
However, this quickly becomes confusing. Instead, use the Character function to return the char you require. In this case 34; chr(34) & myvalue & (chr34).
Worksheets("Sheet2").Range("D2:D" & lastFiltCode).Formula = _
"=SUMIFS(Database!$M$2:$M$" & lastCode & ",Database!$O$2:$O$" & lastCode & ",A2,Database!$I$2:$I$" & lastCode & ","" < "" &$F$1)"
This will do it.
put < in quotes.
First, in order to get <$F$1 inside the formula I use the Chr(34) to add the parenthesis "" inside the formula.
Besides that, you are mixing-up a few things:
Try to avoid using Worksheets("Database").Activate and Worksheets("Sheet2").Activate, and instead use fully qualified worksheets and ranges, like: With Worksheets("Database") and inside lastCode = .Range("O" & .Rows.Count).End(xlUp).Row.
You have Sheet2 and Worksheets("Sheet2"), these two not always mean the same worksheet. You could rename Sheet2 (by code name) to "Something", and that will be your 2nd sheet, and rename Sheet3 (by code name) to "Sheet2" and you have a problem. So decide on which method you want to use (I prefer to use Worksheets("Sheet2")).
Dim lastCode, lastFiltCode As Integer means lastCode is actually Variant and lastFiltCode is Integer. Anyway, it's better to use Long for both of these variables when you are trying to get the last row.
Code
Option Explicit
Sub SumGroups()
Dim lastCode As Long, lastFiltCode As Long
'Determine Last Row in Column O (Unfiltered Codes)
With Worksheets("Database")
lastCode = .Range("O" & .Rows.Count).End(xlUp).Row
'Filter Unique Codes into Column A Sheet2
.Range("O1:O" & lastCode).AdvancedFilter Action:=xlFilterCopy, _
CopyToRange:=Worksheets("Sheet2").Range("A1"), Unique:=True
End With
With Worksheets("Sheet2")
'Determine last Row in Column A (Filtered Codes)
lastFiltCode = .Range("A" & .Rows.Count).End(xlUp).Row
'Place SUMIF Formulas in Columns Sheet2
.Range("B2:B" & lastFiltCode).Formula = _
"=SUMIFS(Database!$M$2:$M$" & lastCode & ",Database!$O$2:$O$" & lastCode & ",A2)"
.Range("D2:D" & lastFiltCode).Formula = _
"=SUMIFS(Database!$M$2:$M$" & lastCode & ",Database!$O$2:$O$" & lastCode & ",A2,Database!$I$2:$I$" & lastCode & "," & Chr(34) & "<" & Chr(34) & "&$F$1)"
.Range("F2:F" & lastFiltCode).Formula = _
"=SUMIFS(Database!$M$2:$M$" & lastCode & ",Database!$O$2:$O$" & lastCode & ",A2,Database!$I$2:$I$" & lastCode & ",$F$1)"
End With
End Sub
i have a debug in my code, but i cannot figure out why it is happening, could you please review the code and see where i messed up? Note the error debug is happening on the ActiveCell.FormulaR1C1 line.
'ENRICHMENT CODE FOR VARIOUS TITLES
For Each wbtitle In wbrange
sThisWorkTitle = wbtitle
sThisWorkColumnNum = wbtitle.Column
sThisWorkColumnNam = Split(Cells(, sThisWorkColumnNum).Address, "$")(1)
'identifying CASH RADICAL COLUMN LETTER
If sThisWorkTitle = "Account Cash Radical" Then
scashradicalcolumnnam = Split(Cells(, sThisWorkColumnNum).Address, "$")(1)
Else
'do nothing
End If
''' CASH RELATED?
If sThisWorkTitle = "Cash Related?" Then
wbtitle.Select
Range(sThisWorkColumnNam + gspstart).Select
ActiveCell.FormulaR1C1 = Application.WorksheetFunction.VLookup(Range(scashradicalcolumnnam & ActiveCell.Row), Range(scashradicalcolumnnam & immsstart & ":" & scashradicalcolumnnam & immsfinal), 1, False)
ActiveCell.AutoFill Range(ActiveCell.Address, Cells(gspfinal))
Columns(sThisWorkTitle).Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues
Else
'do nothing
End If
Scott has highlighted the problem line.
You could try amending so an actual formula is inserted into the cell.
So instead of the following:
ActiveCell.FormulaR1C1 = _
Application.WorksheetFunction.VLookup( & _
Range(scashradicalcolumnnam & ActiveCell.Row) & _
, Range(scashradicalcolumnnam & immsstart & ":" & scashradicalcolumnnam & immsfinal), 1, False)
Something like:
ActiveCell = "=vlookup(" & scashradicalcolumnnam & ActiveCell.Row & _
"," & scashradicalcolumnnam & immsstart & ":" & _
scashradicalcolumnnam & immsfinal & _
", 1, False)"
Really quick question on how to format VBA in excel formulas. When you are inserting a formula into excel and you want to insert a variable from vba for example if b is a string you would use " & b & " is that the correct formatting? To illustrate the problem I have the code below and tried to use that formatting and well... I don't know why it wont work, I get a (Compile error: Expected: End of statement). Can anyone tell me where I am going wrong?
Dim HrsSTD As String
Dim HrsSAT As String
Dim HrsSUN As String
Dim HrsSTWN As String
Dim sdFormula
HrsSTD = ActiveCell.Address
Selection.Offset(0, 1).Select
HrsSAT = ActiveCell.Address
Selection.Offset(0, 1).Select
HrsSUN = ActiveCell.Address
Selection.Offset(0, 1).Select
HrsSTWN = ActiveCell.Address
sdFormula = "=IF((" & Range(NamedRange).Cells(2, 1).Address & _
"=""Please add a title"",0,VLOOKUP((" & Range(NamedRange).Cells(2, 1).Address & _
",'Tables (H)'!$H$2:$J$6,2,FALSE)* _
" & HrsSTD & "+VLOOKUP(" & Range(NamedRange).Cells(2, 1).Address & _
",'Tables (H)'!$H$2:$J$6,2,FALSE)* _
" & HrsSAT & "*1.25+VLOOKUP((" & Range(NamedRange).Cells(2, 1).Address & _
",'Tables (H)'!$H$2:$J$6,2,FALSE)*" & HrsSUN & "* _
1.5+VLOOKUP((" & Range(NamedRange).Cells(2, 1).Address & _
",'Tables (H)'!$H$2:$J$6,2,FALSE)*" & HrsSTWN & "*0.75)"
The code I would type into excel would be: But I want to change the A13's and the I16 (i.e. all the relative references) into variables in VBA
=IF(A13="Please add a title",0,VLOOKUP(A13,'Tables (H)'!$H$2:$J$6,2,FALSE)*F16+VLOOKUP(A13,'Tables (H)'!$H$2:$J$6,2,FALSE)*G16*1.25+VLOOKUP(A13,'Tables (H)'!$H$2:$J$6,2,FALSE)*H16*1.5+VLOOKUP(A13,'Tables (H)'!$H$2:$J$6,2,FALSE)*I16*0.75)
Is this what you are trying? Also I see that you haven't taken my advice from the previous answer.
One more tip. Break you code in simple parts. It is easier to understand.
The problem with your code is in the line
",'Tables (H)'!$H$2:$J$6,2,FALSE)* _
" & HrsSAT & "*1.25+VLOOKUP((" & Range(NamedRange).Cells(2, 1).Address & _
You can't write it like that. The first line doesn't have the ending ". You cannot carry it forward to the next line like that.
is this what you are trying?
Dim sFormula As String
Dim sAddr As String
sAddr = Range(NamedRange).Cells(2, 1).Address
sFormula = "=IF(" & sAddr & _
"=""Please add a title"",0,VLOOKUP(" & _
sAddr & ",'Tables (H)'!$H$2:$J$6,2,FALSE)*F16+VLOOKUP(" & _
sAddr & ",'Tables (H)'!$H$2:$J$6,2,FALSE)*G16*1.25+VLOOKUP(" & _
",'Tables (H)'!$H$2:$J$6,2,FALSE)*H16*1.5+VLOOKUP(" & _
sAddr & ",'Tables (H)'!$H$2:$J$6,2,FALSE)*I16*0.75)"