i need to write vba code wherein cell GQ4 has formula
ActiveCell.Formula = "=SUM(CO4:CQ4)"
Now there is new month added every month in excel data hence the formula will also change dynamically every month.
ie next month it will be
"=SUM(CP4:CR4)"
in short it is dragging its column selection by 1 column
Please help me write a vba code that will dynamically change the formula.
Note sure if it is possible to return a formula from a custom function, but a solution might be to write a custom function that returns the range you want, and then have the formula in GQ4 take the range as an argument.
Or you can solve it with a normal worksheet formula.
=SUM(INDIRECT(ADDRESS(4;15));INDIRECT(ADDRESS(4;16));INDIRECT(ADDRESS(4;17)))
Replace the column numbers with a base + offset that you can get by using a date function. E.g.
=SUM(INDIRECT(ADDRESS(4;14 + =MONTH(TODAY())));INDIRECT(ADDRESS(4;15 + =MONTH(TODAY())));INDIRECT(ADDRESS(4;16 + =MONTH(TODAY()))))
Related
I'm attempting to convert the formulas in a sheet into VBA code in a macro, and am stumped by the following:
{=IF(ISNA(MATCH($A8&$B8&$C8&E$7,'Raw Data'!$E:$E&'Raw Data'!$D:$D&'Raw Data'!$C:$C&'Raw Data'!$G:$G,0)),"","Yes")}
It's trying to look at multiple columns in one sheet, compare them to another, and see if the value of the column header is in the fourth column "G" to return "Yes" or blank. I've attached a screenshot of the sheet it fills out:
This array formula will take a long time to compute, since each column has over one million rows. Array formulas should not use whole column references.
The same result can be returned with a non-array formula, which can be used in VBA without any special commands.
=IF(ISNA(MATCH($A8&$B8&$C8&E$7,Index('Raw Data'!$E$1:$E$1000&'Raw Data'!$D$1:$D$1000&'Raw Data'!$C$1:$C$1000&'Raw Data'!$G$1:$G$1000,0),0)),"","Yes")
If you want to use an array formula in VBA, you will need .FormulaArray instead of .Formula or .FormulaR1C1
If you don't want to enter a formula into a worksheet cell, but perform the calculation in VBA, you can use Worksheetfunction (https://learn.microsoft.com/en-us/office/vba/api/excel.worksheetfunction) to use the worksheet functions and their syntax.
We need a script to compare the dates in column D to the dates in column E.
If the date in column D is two days before the date in column E then we need column F to state that in the corresponding row to D. We have a range of 2 days before and 2 days after (shoulder days). We need to be able to easily reproduce this and have it be able to run when we import it into access. we have roughly 3300 unique days to check.
I have tried using datevalue or a formula but we need to be able to reproduce this in the future and the formula doesn't allow us to easily do that.
I will not provide a complete implementation, but I can show you the way how you can do it (either the Excel formula way or with VBA code). Both ways will automatically calculate the values you need so you can easily import it into Microsoft Access - the import will take the calculated values from the cells you've selected.
The first way, which is also the simplest way, is to do that with simple Excel formula, consider this picture showing how the formula will calculate the values in columns F and G:
(Note: It is showing German date format, but you can easily change that in Excel).
In column G it calculates the difference D2 - D1 and displays it in days.
Then, in column F there is a simple if condition to determine if the date D1 is less, greater or equal than D2. The Result is calculated automatically.
The formula in row 2 are:
Hint: You can drag and drop the formula to the rows 3 - n below, so you can create a lot of rows prefilled with that formula.
A second way is that you can write a VBA function for the (simple) calculation formula in column F:
Function CalcResult(D1 As Variant, D2 As Variant) As Variant
CalcResult = ""
Dim result As String
Dim diff As Single
diff = D2 - D1
If (diff > 0) Then
result = "D1 < D2"
ElseIf (diff = 0) Then
result = "D1 = D2"
ElseIf (diff < 0) Then
result = "D1 > D2"
End If
CalcResult = result
End Function
This needs to be entered in the VBA editor, which you can display if you press Alt+F11. After you have done that, press Alt+F11 again to close VBA and return to your Excel sheet.
Then, place the formula =CalcResult(E2; D2) in cell F2 as shown below:
Like in the previous example, you can drag & drop the formula to the rows 3 - n below, so you can create a lot of rows prefilled with that formula.
The advantage of the 2nd approach is that you can refine the function CalcResult later without having to change the cells again (as it is the case in the first example).
Note: The function above needs to be in a separate module and you need to save the workbook as "Macro enabled workbook" later - otherwise you'll lose the VBA code.
A third way is to use the Excel macro recorder and record whatever you intend to do. It will create a public module with VBA code. If the recorder asks you, choose to store the code in the workbook.
Later you re-visit the generated VBA code and refine it - for example, put a for loop around it to automate things you've recorded once.
This approach is good for creating a "Calculate" button and put some logic behind it.
This is my first post and I can't find an exact answer anywhere. I have an Excel spreadsheet that is becoming too large to operate because I have long formulas in millions of cells. I need to know how to calculate the formula using VBA but have only the value appear in Excel. An example is I want to multiply column B by column C:
I have tried this code:
Range("D3:D6").Formula = Evaluate("=B3*C3")
It correctly calculates for the first cell, but for the other cells it still tries to calculate B3*C3 as a fixed reference rather than as a dynamic references that changes as the cell position changes.
How could I fix this? Thankyou.
Edit:
My actual spreadsheet looks like this:
This formula needs to be applied down 17520 rows and across 300 columns, but I only want the values to appear in Excel. The purpose of this is to reduce file size and reduce calculation time.
=IF(-SUMIF(AIG$4:AIG4,"<0")>0.9*SUMIF(AIG$4:AIG4,">0"),0,IF(-SUMIF(AIG$4:AIG4,"<0")-IF(WQ5<'Battery Specs'!$B$13,-'Battery Specs'!$B$15,IF(WQ5=ROUNDDOWN('Battery Specs'!$B$13,0)+1,-('Battery Specs'!$B$13-ROUNDDOWN('Battery Specs'!$B$13,0))*'Battery Specs'!$B$15,0))>0.9*SUMIF(AIG$4:AIG4,">0"),-(0.9*SUMIF(AIG$4:AIG4,">0")+SUMIF(AIG$4:AIG4,"<0")),IF(WQ5<'Battery Specs'!$B$13,-'Battery Specs'!$B$15,IF(WQ5=ROUNDDOWN('Battery Specs'!$B$13,0)+1,-('Battery Specs'!$B$13-ROUNDDOWN('Battery Specs'!$B$13,0))*'Battery Specs'!$B$15,IF((0.9*SUMIF(AIG$4:AIG4,">0")+SUMIF(AIG$4:AIG4,"<0"))>'Battery Specs'!$B$10,0,IF(((0.9*SUMIF(AIG$4:AIG4,">0")+SUMIF(AIG$4:AIG4,"<0"))+$AIF5*0.9)>'Battery Specs'!$B$10,'Battery Specs'!$B$10-(0.9*SUMIF(AIG$4:AIG4,">0")+SUMIF(AIG$4:AIG4,"<0")),$AIF5))))))
Try
Range("D3:D6").Formula = "=B3*C3"
Range("D3:D6").Value = Range("D3:D6").Value
or simply
Range("D3:D6").Formula = Evaluate("(B3:B6)*(C3:C6)")
Using Evaluate to calculate the formulas and then transfer the values to Excel will be slower than having Excel calculate the formulas directly.
Here are a couple of things you could try:
a) Formulas
You only have 5 million formulas in 5 million cells - this is not an overwhelmingly large number but your formulas are very long and each formula references a large number of cells.
Your formula contains many repeated expressions and calculations - move them out to helper cells and try to simplify/shorten your formula.
b) VBA - don't use Evaluate - just grab the range of 5 million cells into a single variant array and use VBA Loops, arithmetic and logic to accomplish the same task as your formulas and then put the array back.
I believe best option is to keep formulas instead of using VBA to produce same formulas. Instead, when entering new data in SpreadSheet, be sure to set calculations to manual (go to Formulas tab=>Calculation Options=>Manual. This way you wont trigger calculations when entering/pasting new values, meaning your Excel file will operate just as fast as if there was no formulas. After you entered/pasted all new values, set Calculations to Automatic.
You might want to try this:
Dim i as Integer
For i = 3 to 6
Range("D" & i).Value = Range("B" & i).Value * Range("C" & i).Value
Next i
The other alternative is to name your formula, for instance, instead of saying =B3*C3, you can give it a name say times value, and then say =timesvalue. Next, remove the formula and leave the value only. E.g. range("D3:D30").value=range("D3:D30").value
I have months in my column header and I want Excel to Fill them in sequentially. It currently does this by default but it is filling in the long month even though it understands my short month.
Eg: I manually wrote in 'Sep' for September but it fills 'October' in the next column instead of 'Oct.'
I know Excel has both versions of months stored in it's default Custom Lists. How do I get it to switch?
You can use this formula :
=Text(A1,"mmm")
Where A1 is the cell/column/row, thus u can change it to your requirements.
After typing that formula drag it along the following rows and it will apply the formula accordingly.
Also for further refrence and/or questions u may also check this.
You can use this Formula in VBA to fill the rest of the months:
[A1] = "May"
[B1:L1].Formula = "=TEXT((A1 & "" 1"") + 50, ""mmm"")"
[B1:L1] = [B1:L1].Value2 ' optional to convert the formulas to values
Currently I have a couple of SUM functions setup in my worksheet.
Lets use H2:H34 for my example: If I add a row within that range, the sum function will automatically adjust. The problem is when I add new rows, it is below the range (below H:33). In this case, I would just have to highlight the column and expand/drag the range to where it needs to be. There are a total of 8 columns that are doing a sum function. Is this only possible by using a macro?
=SUBTOTAL(3,H2:H34)
With your formula being the extent of the range minus one row we can use this:
=SUBTOTAL(3,H2:INDEX(H:H,ROW()-1))
Now as rows are added or deleted the reference will remain intact.
If there is a chance that row 2 would be deleted you will get #Ref errors. To avoid that you can use this formula:
=SUBTOTAL(3,INDEX(H:H,2):INDEX(H:H,ROW()-1))
Now there are no specific cell references and adding or deleting will not effect the formula and the range will be dynamic.
you could use a named range like =sum(range1) and something like;
Select first empty cell in column F starting from row 1. (without using offset )
to find the first empty cell to change the reference for the named range.
Triggering it would be difficult... potentially could use on_save?
or option 2.... bit of a dodge, but can work....
you say your sum is in cell H35... maybe move it to h36, and create a dummy hidden row in 35 (0.1 row height). that way when you add a row, it is always above 35. Use sum H1:H35 and it will always auto update? its not a neat solution, but should work
Use the following code, you need to adjust column "H" to whatever column you need.
Dim sumtest As Variant
sumstest = Application.WorksheetFunction.Subtotal(9, Range("H2:H" & ActiveSheet.Cells(ActiveSheet.Rows.Count, "H").End(xlUp).Row))