Insert Sum(sumif in VBA for multiple criteria, using formulaR1C1 - excel

Cannot get SUM(SUMIF to work with VBA, yields “Run-time error 1004”. SUM(SUMIF is typically used in Excel to sum using multiple criteria.
This is my formula.
Worksheets("units").Cells(i, j).FormulaR1C1 = "=pws!R[0]C[0]+SUM(SUMIF(pws!R1C3:R1C" & (2 + numlxp) & ",central!C[1]R3:C[1]R" & (2 + numatt) & ",pws!R[0]C3:R[0]C" & (2 + numlxp) & "))"
I also tried a version using OFFSETS instead of R1C1. The OFFSETS versions works within Excel itself, but not in VBA.
I then tried simplifying to the below, to see if there was an issue with SUM(SUMIF specifically within VBA, but it returns a formula with # for implicit intersectionality and gives the wrong result ‘0’:
Worksheets("units").Cells(2, 2).Formula = "=SUM(SUMIF(pws!C1:L1,central!C3:C6,pws!C2:L2))"

Try using SUMPRODUCT combined with unary operator:
Yellow cells would be the criteria (in your case, central!C3:C6).
Formula in cell C6 is:
=SUMPRODUCT(--(COUNTIF($A$6:$A$7,$C$1:$L$1)>0)*$C$2:$L$2)
Formula in cell C7 is:
=SUMPRODUCT(--($C$1:$L$1=$A$6:$A$7)*$C$2:$L$2)
First formula ignore duplicates in criteria and second one does not. Second one is easier to implement but if your criteria has duplicate values, it will duplicate result, so watch out and choose wisely. Just as example, notice if both of my criterias are the same, each formula returns a different output:
Anyways, when you are done choosing, you should be able to implement this in VBA code like this (or kind of):
Worksheets("units").Cells(2, 2).Formula = "=SUMPRODUCT(--(COUNTIF(central!$C$3:$C$6,pws!$C$1:$L$1)>0)*pws!$C$2:$L$2)"
SUMPRODUCT and Double Unary
Operators

Related

Application.Evaluate Does not work with SUMIF with ">" or "<" condition

I'm trying to use Application.Evaluate method for evaluating a Sumif formula in which the criteria is ">="
Following is the line of code I'm trying to get an evaluation of
So I have Order Numbers 1 to 15 in Cell E1 to E15, and their Respective Amounts in Cell F1 to F15.
In J1 the user inputs his Order Number. Amount over and above that order number will be totaled and displayed using Sumif Function.
Now I want to find this answer using Application.Evaluate
MsgBox( Application.Evaluate("=SUMIF(E1:E15, ">=" & J1, F1:F15)"))
I get greeted with True or False Message Box.
Now I am guessing the inverted commas in Sumif Function ie. ">=" is causing this problem. Hence to fix this, I amended the function to
MsgBox( Application.Evaluate("=SUMIF(E1:E15, """">="""" & J1, F1:F15)"))
However now it returns 0, although there are values in it.
I would really appreciate if someone could help me understand a way around it
*Note: Please do not suggest to use any other function. I want to know it purely from Application.Evaluate perspective, as my further line of code depends on it. *
Thanks.
All quotes inside the string must be doubled:
">="
Should be
"">=""
Also:
Application.Evaluate
will work on the active sheet, thus if the wrong sheet is active the sumifs will be done on the wrong sheet since no sheet names are provided in the formula itself.
Use
Worksheets("Sheet1").Evaluate
Changing "Sheet1" to your sheet.
So in total:
MsgBox Worksheets("Sheet1").Evaluate("=SUMIF(E1:E15, "">="" & J1, F1:F15)")

Calculate Excel formulas in VBA but display only the value in Excel

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

Excel VBA should run excel function - RIGHT LEN

I would like to put the below coding into a vba like a function. There is a bunch of data created already by VBA, and when the VBA does its work, then the following function should be run, but i dont know how to add to my vba so that the function always runs as long as data contains. The macro i created already puts the datasheet together, now instead of creating the below with lenthy codings, i just want my macro to run the below, like a man who clicks on the below right hand corner of the cell which contains the below function.
It should be something: Activesheet.ForulaR1C1 = "=RIGHT(AY4,LEN(AY4)-FIND(".",AY4))" something. Can someone help me? Thanks
ORIGINAL FUNCTION TO BE RUN "=RIGHT(AY4,LEN(AY4)-FIND(".",AY4))"
This is where I am at now:
Sub Project_numbers()
Dim j As Integer
Zorro = Range("AY" & Rows.Count).End(xlUp).Row
o = 4
Worksheets("MJE").Range("AF" & o).FormulaR1C1 = "=RIGHT(AE4,LEN(AE4)-FIND(".",AE4))"
o = o + 1
End Sub
You have a couple of problems here. The biggest is that you've got quotation marks in your formula. VBA reads these as the end of the string, so it's interpreting your formula as two separate text strings: =Right(AE4,LEN(AE4)-FIND( and ,AE4)), separated by a .. This isn't a structure VBA can do anything with, so it's going to fail at that point.
When you're inserting a formula with VBA that contains quotation marks, you need to use two quotes together to indicate that it's a literal quote mark that's part of the string, rather than the end of the string:
"=RIGHT(AE4,LEN(AE4)-FIND(""."",AE4))"
The second problem is that you're using the FormulaR1C1 method, which expects cell references to be given in R1C1 (row#column#) notation, rather than A1 notation, but then passing it a formula that uses A1 notation. Again, this is going to confuse the issue and produce errors.
I'm guessing you used the macro recorder to get the syntax, then inserted your own formula? The macro recorder, for some weird reason, loves to use the R1C1 reference style, but we can use a different method for written code.
The full line you need is:
Worksheets("MJE").Range("AF" & o).Formula = "=RIGHT(AE4,LEN(AE4)-FIND(""."",AE4))"
EDITED TO ADD:
With further information, specifically that you need the range referenced to change as you loop, you have some options on how to do it.
1. Use the R1C1 reference style
This allows you to include relative references in formulae easily. You'll use R to designate the formula's row, and C to designate its column; so a cell that referred to itself would simply be =RC. You can follow the R and C with numbers to designate specific rows and columns, so cell B2 would be =R2C2 - row 2, column 2. More usefully, you can use =R[#]C[#] to offset your formula by a certain amount.
In your formula, assuming it's always going to be looking at column AE but whichever row the formula is entered into, your line would be:
Worksheets("MJE").Range("AF" & o).FormulaR1C1 = "=RIGHT(RC31,LEN(RC31)-Find(""."",RC31))"
2. Build your formula from variables.
You already have a variable you can use, o, so we can combine that with the rest of the string to get the appropriate references. It's harder to read, though...
Worksheets("MJE").Range("AF" & o).Formula = "=RIGHT(AE" & o & ",LEN(AE" & o & ") - FIND(""."",AE" & o & "))"
Personally, I find this method rather cumbersome to work with, but it's an option.
3. Assign the formula to your entire range as a single operation
Personally, I prefer this option; I find it to be the neatest one. I'm assuming, from your formula, that your data starts on row 4, and you want the formula to go into every cell between AE4 and the end of your data, which is stored in Zorro. You can use this line to add the formula in one go:
Worksheets("MJE").Range("AF4","AF" & Zorro).Formula = "=RIGHT(AE4,LEN(AE4)-FIND(""."",AE4))"
The cell references will update automatically for each row. There's no need for a loop with this method - of course, if you're looping anyway, that may be no great saving.

Dynamic formula with quotes inside a COUNTIFS function

I am trying to adapt the following formula (counting instances of values between 0 and 24):
=COUNTIFS(cancellations!AG2:AG408,">0",cancellations!AG2:AG408,"<24")
(formula evaluates to 75), to something like:
=COUNTIFS(cancellations!AG2:AG408,">0",cancellations!AG2:AG408,INDIRECT("" & "<" & B1*24 & ""))
but this evaluates to zero. (B1 = 1 in the above example.)
When I view the INDIRECT function inside the fx box it evaluates correctly. Not sure of what I am doing wrong.
When applied in a cell like so:
=INDIRECT("" & "<" & B1*24 & "")
It shows #REF!.
The INDIRECT function returns a reference to a range. You can use this function to create a reference that won't change if row or columns are inserted in the worksheet. Or, use it to create a reference from letters and numbers in other cells.
=COUNTIFS(cancellations!AG2:AG408,">0",cancellations!AG2:AG408,B1)
should work where B1 contains <24.
So, I read up the COUNTIFS() function in more detail and I found that the following works
=COUNTIFS(cancellations!AG2:AG408,">0",cancellations!AG2:AG408,"<"&B1*24)
Where:
B1=1

HLOOKUP in R1C1 notation

I'm using Excel VBA to insert an HLOOKUP function at the end of a given row. I've been attempting to use the R1C1 functionality in VBA for inserting the HLOOKUP function, which should appear as follows in Excel:
=HLOOKUP(D2,'DM NYASSOV'!3:34,32,0)
My issue is that I need the HLOOKUP to be dynamic enough that it can reference variables from the same row on which the HLOOKUP function is to be pasted.
Currently my VBA reads as follows:
ThisWorkbook.Sheets(selectTab).Cells(r, 21).FormulaR1C1 = "=HLOOKUP(RC[-17],'DM RC[-19]!'RC[2]:RC[3],RC[3]-RC[2]+1,0)"
RC[-17] references the variable I'm looking for;
RC[-19] is the underlying book/tab identifier;
RC[2] contains the initial row value, and
RC[3] contains the final row reference range.
My main issue is with correctly identifying the dynamic range selection:
'DM NYASSOV'!3:34 / 'DM RC[-19]!'RC[2]:RC[3]
Any pointers are greatly appreciated.
I think you have a few issues here. First is using VBA to dynamically build a formula that then calculates a third value that then gets used in the formula which finally calculates a result. This seems like an unnecessary amount of runaround for a value that can be done with either a formula built on the front end or calculated via VBA in the back end. The second is all the dynamic lookup of it all. It's not so much a problem, but rather a lot to keep track of as you jump through the four hoops. Just the same...
The first parameters of your HLOOKUP can either be a value like "SM1804" or a reference to a cell that contains "SM1804". You can either use VBA to bring this value directly into the formula and save Excel some processing by having to lookup that value at formula processing time:
ThisWorkbook.Sheets(selectTab).Cells(r, 21).FormulaR1C1 = "=HLOOKUP(" & Sheets(selectTab).Cells(r, 21).Offset(0, -17).value & ",'DM RC[-19]!'RC[2]:RC[3],RC[3]-RC[2]+1,0)"
Or you can stick the reference to the cell in there (which is what you are doing now):
ThisWorkbook.Sheets(selectTab).Cells(r, 21).FormulaR1C1 = "=HLOOKUP(RC[-17],'DM RC[-19]!'RC[2]:RC[3],RC[3]-RC[2]+1,0)"
On to the second parameter... I believe you have a sheet name in DM!RC[-19] This is totally OK, but you'll need to use 'Indirect' to get that sheet name into the HLOOKUP formula:
ThisWorkbook.Sheets(selectTab).Cells(r, 21).FormulaR1C1 = "=HLOOKUP(RC[-17],Indirect("'" & DM!RC[-19] & "'!RC[2]:RC[3]"),RC[3]-RC[2]+1,0)"
...this is where things get a little tricky. If, for instance, in DM!RC[-19] you have the sheetname "Sheet1" then indirect is going to return: 'Sheet1'!RC[2]:RC[3] and your HLOOKUP will use that range to do the lookup... Doesn't make a lot of sense to do a HLOOKUP on a range with two cells. So I assume that you have number values in RC[2] and RC[3] there that represent rows. So really the indirect would have to look like:
ThisWorkbook.Sheets(selectTab).Cells(r, 21).FormulaR1C1 = "=HLOOKUP(RC[-17],Indirect("'" & DM!RC[-19] & "'!R" & RC[2] & "C:R" & RC[3] & "C"),RC[3]-RC[2]+1,0)"
Now if your RC[2] has the value "4" and your RC[3] has the value "20" your indirect will return: 'Sheet1'!R4C:R20C and your HLOOKUP will use that value as the range in which it will look up.
You are also doing some math on those values in RC[2] and RC[3], so that's probably all good and doesn't need to be changed. You just need to keep in your head what VBA is going to return as a formula, and then what that formula is going to get from Indirect and then what the resulting HLOOKUP is going to find.
It's a lot to keep track of and may be simplified just by writing the formulas directly in the cell and copying down, or just doing the HLOOKUP functionality directly in VBA.

Resources