Sumproduct in macro - excel

I am trying to make a macro using the SUMPRODUCT function together with SUMIF.
but when I run the macro I get …
run-time error 13.
I have tryed to make the same function just in a cell looking like this.
=SUMPRODUCT(SUMIF(B2:B3,K15:K18,L15:L18))
and it works fine, so I know the concept is proven.
Sub GrandTotal() 'Finds the last non-blank cell in a single row or column
Dim lRow As Long
Dim lCol As Long
Dim GrandTotal As Variant
Dim MyRg1 As Variant
Dim MyRg2 As Variant
Dim MyRg3 As Variant
'Find the last non-blank cell in column A(1)
lRow = Cells(Rows.Count, 1).End(xlUp).Row
'Find the last non-blank cell in row 1
lCol = Cells(1, Columns.Count).End(xlToLeft).Column
MsgBox "Last Row: " & lRow & vbNewLine & _
"Last Column: " & lCol
'set range
Set MyRg1 = Range("B2:B3")
'set criteria
Set MyRg2 = Range("$K$15:$K$18")
'set sum range
Set MyRg3 = Range("$L$15:$L$18")
For Each cell In Range(Cells(lRow, 2), Cells(lRow, lCol))
GrandTotal = WorksheetFunction.SumProduct(WorksheetFunction.SumIf(MyRg1, MyRg2, MyRg3))
cell.Value = GrandTotal
Next cell
End Sub
I have found some guides how to use the function in VBA and I followed the same princip, also i saw an other post here on stack that showed how to do, and yet I get the error.
hope some kind soul can help

First, each variable that is being assigned a Range object can be declared as a Range, instead of Variant. Also, the ranges that are being passed to SUMIF don't seem correct. The first argument or criteria range should be the same size as the third argument or sum range. So I am going to assume that the ranges assigned to MyRg1 and MyRg2 should be the other way around. So to start with we should have the following...
Dim MyRg1 As Range
Dim MyRg2 As Range
Dim MyRg3 As Range
'set criteria range
Set MyRg1 = Range("$K$15:$K$18")
'set criteria
Set MyRg2 = Range("B2:B3")
'set sum range
Set MyRg3 = Range("$L$15:$L$18")
Secondly, you won't be able to use WorksheetFunction.Sumproduct that way. You can, however, use the Evaluate method..
GrandTotal = Evaluate("SUMPRODUCT(SUMIF(" & MyRg1.Address & "," & MyRg2.Address & "," & MyRg3.Address & "))")
Note, though, the Evaluate method has a limitation. It does not accept more than 255 characters. In any case, since you want to transfer the result to a cell, you can first enter the actual formula in the cell, and then convert it into a value...
With cell
'enter the formula in the current cell
.Formula = "=SUMPRODUCT(SUMIF(" & MyRg1.Address & "," & MyRg2.Address & "," & MyRg3.Address & "))"
'convert the formula into a value
.Value = .Value
End With
Hope this helps!

After you have your function working, you can turn on the Macro Recorder, click the cell with the function you need, hit F2, and hit Enter. You will have VBA that does what you want.

Error 13 is a Type mismatch error. I looked up the documentation of WorksheetFunction.SumIf. It says the first argument should be of type Range, and the second and third a Variant. I can not test now, but try to declare MyRg1 as a Range.

This would be a good use for ConvertFormula since you have successfully built the formula in Excel, you just need VBA to generate the value. Note that convertformula cannot handle formulas over 255 characters.
Here's roughly how you could apply it. It's
Sub heresExample()
'formula with the cell in exitance
Dim fCell As Range
Set fCell = Range("G10") 'set this up with a formula that works for
'if you were to copy paste formula.
'Your original code modified
Dim cell As Range
For Each cell In Range(Cells(lRow, 2), Cells(lRow, lCol)).Cells
'Takes the formula and applies the value if from that exact cell.
'(you don't really need grand total)
GrandTotal = Evaluate(Application.ConvertFormula(fCell.Formula2R1C1, xlR1C1, xlA1, , cell))
cell.Value = GrandTotal
Next cell
End Sub

Related

How do I make my SumIf Function run through until last range of my data on VBA Code

Here is my SumIf Formula
=SUMIF($C$26:$C$43,$C$6,D26:D43)
The C6 is fixed so I lock it so the cell won't run if I drag it
The problem is the range and the sum range
The starting row column of the range (C26) and the sum range (D26) are always the same but not for the last row because my data quantity is not always the same (sometimes it goes until 100 sometimes less)
How can I change the VBA formula of the SumIf to match exactly the same quantity of my data?
here's my SumIf VBA Code (Got it from the record it)
"=SUMIF(R26C3:R43C3,R6C3,R[20]C:R[37]C)"
Please, try the next way. The code must determine the last cell in C:C and then use it. There are more possibilities to do that. As the following code does, or using directly in the string formula, replacing (existing) 43 ("=SUMIF($C$26:$C$" & lastR ...:
Sub formulaUntilLast()
Dim lastR As Long, rngC As Range, RngD As Range, strFormula As String
lastR = ActiveSheet.Range("C" & rows.count).End(xlUp).row
Set rngC = Range("C26:C" & lastR)
Set RngD = Range("D26:D" & lastR)
strFormula = "=SUMIF(" & rngC.Address & ",$C$6," & rngC.Address & ")"
Debug.Print strFormula
End Sub

Making the criteria in a SUMIF function relative to the active cell

Here is a simplified version of my data
Here is the formula I am entering
In D22 I need to enter the same SUMIF formula but the criteria is `ActiveCell.Offset(-1, -1)'. How can I create this macro? I have close to 570 rows and data similar and need to condense the dates into just one.
Thanks
I expect the macro to be able to input the sumif formula referencing the range as column $C, the criteria as $ActiveCell.Offset$(-1,-1) and the sum range as the column of the active cell so D but not locked as the sum range will change.
Declare and set Range variables to the various ranges you require, then build the formula from those variables .Address properties. Use the various parameters of Address to set the required Absolute/Relative addressing and External references
Sub EnterSum()
Dim rCritera As Range
Dim rCriteriaRange As Range
Dim rSum As Range
Dim rFormula As Range
Set rCriteriaRange = ActiveSheet.Columns(3)
Set rCritera = ActiveCell.Offset(-1, -1)
Set rSum = ActiveCell.EntireColumn
Set rFormula = ActiveCell 'Q doesn't specify this cell, so adjust as needed
rFormula.Formula = "=SumIf(" & rCriteriaRange.Address(1, 1) & "," & rCritera.Address(1, 1) & "," & rSum.Address(0, 0) & ")"
End Sub
Example: if ActiveCell is D5 then result is =SUMIF($C:$C,$C$4,D:D)

How to use cell contents as inputs for range formulas in Excel VBA?

Excel VBA range formula is something like Sheet2.Range("A1").value.
You can, for example, refer to this address and change the value in that cell.
Now what I am looking for is to build this formula by using the contents of two cells; one cell says "Sheet2" and the other says "A1". How can I refer to these two cells in a formula so that it works the same way?
I have tried various dims and now end up without an error but not with the desired result. The current formula simply returns "Sheet2.Range("A1").value instead of its contents.
Sub AddressInCells()
'This is just for one reference. In reailty there is a table of references to loop through.
'For this example cell A1 in Sheet2 = "Text to take to sheet1"
Dim SheetSel As String
Dim CellSel As String
Dim ReferSel As String
With Sheet1
SheetSel = Cells(1, 1).Value
CellSel = Cells(1, 2).Value
ReferSel = SheetSel & ".range(" & Chr(34) & CellSel & Chr(34) & ").value"
MsgBox ReferSel
Sheet1.Range("D1").Value = ReferSel 'Results in "Sheet2.range("A1").value
Sheet1.Range("D2").Value = Sheet2.Range("A1").Value 'Results in Text to take to sheet1'
End With
End Sub
The expected result is that the formula works the "usual" way. It now simply returns a string.
I believe, instead you want to do:
ReferSel = Sheets(SheetSel).range(CellSel).value
You could try:
Option Explicit
Sub test()
Dim ws As Worksheet
Dim rng As Range
'With statement where the data are store. Change name if needed
With ThisWorkbook.Worksheets("Sheet1")
Set ws = ThisWorkbook.Worksheets(.Range("A1").Value)
Set rng = ws.Range(.Range("A2").Value)
End With
Debug.Print rng.Address
Debug.Print rng.Worksheet.Name
End Sub
You're trying to build a formula string, which follows this convention:
'<sheet name>!'<address>
The single-quotes are only strictly required if the sheet name contains a space, so this would be a valid formula:
=Sheet1!$A$1
But it's just good habit to always include them, so, you need to build your string from the values in those cells:
' offset the sheet name in single quotes, separate the sheet & address with !
ReferSel = "='" & SheetSel "'!" & CellSel
Sheet1.Range("D1").Formula = ReferSel

How to concatenate text from a column into a new column? VBA Excel

I'm new to vba programming and I would like to work on a function to fix salutations in an excel file.
To start, I would just like to append a Dear " to a name in the first column, and put this value in the next column, so that I would end up with the name in the first column and "Dear name" in the next column.
The function I have so far, is putting "Dear " in the next column, but it is not appending that to the text in the first column. Could someone help me correct my code?
Sub letterSalutationFixer()
Dim letterSalutationColumn As Range
Set letterSalutationColumn = Columns(1)
For Each Cell In letterSalutationColumn
Cell.Offset(, 1).Value = "Dear " & Cell.Text
Next
End Sub
PS. I do realise that I don't necessarily need to do this programmatically since it doesn't take that long to do with the functions already available, but I eventually want to expand this to fix other data with more complexity - and just thought I could start with something simple.
Many thanks in advance!
The reason it's blank is that Cell is equivalent to the whole column. You're close though. If you did...
For Each Cell In letterSalutationColumn.Cells
..l it would cycle through each cell.
However, the way it's written, it would cycle through each cell in the whole column, which could crash Excel, or at least slow things way down.
Here's a reworked version of what you're trying to do. It only acts on the cells in column A with content:
Sub Salutation()
Dim ws As Excel.Worksheet
Dim LastRow As Long
Dim NameRange As Excel.Range
Dim cell As Excel.Range
Set ws = ActiveSheet
With ws
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
Set NameRange = .Range("A2:A" & LastRow)
For Each cell In NameRange
cell.Offset(, 1) = "Dear " & cell.Text
Next cell
End With
End Sub
It also declares all variables, something you want to get in the habit of doing. Do a search on Option Explicit to learn how to force yourself to.
It also uses a With statement to fully qualify Object references, so that instead of just referring to Column(1) or Range(something) you're specifying that it's in ws, which has been set to the ActiveSheet.
Another way is the VBA alternative of
Using a formula in column B that runs the concatenation against the used part of column A (ie in B1 ="Dear " &A1 etc)
The formula then is copied over itself as a value to remove the formula
code
Sub QuickCon()
Dim rng1 As Range
Set rng1 = Range([a1], Cells(Rows.Count, "A").End(xlUp))
With rng1.Offset(0, 1)
.FormulaR1C1 = "=""Dear "" &RC[-1]"
.Value = .Value
End With
End Sub

Excel VBA Vlookup issue

I'm a complete beginner to Excel VBA.
The following is code I've written that should iterate through a column in a sheet, filling values by referring to the column value to it's left and referring to another sheet in the same workbook to find what the correct corresponding value should be.
I've used a While loop so i can apply this VLOOKUP macro to each cell in the column ( only the lookup value, changes, which should be a variable denoting the column to the left) :
Dim result As String
Dim sheet As Worksheet
Dim rownum As Integer
Dim iterator As Integer
Dim lookup_value As String
Dim vlookupString1 As String
Set sheet = ActiveWorkbook.Sheets("datasheet")
rownum = sheet.Range("A1").End(xlDown).Row
Set iterator = 3
While iterator < rownum
lookup = "M" & iterator
vlookup1String = "=VLOOKUP(" & lookup & ",'GICS Sub-industry codes'!$A$2:$B$155,2,FALSE)"
With ActiveSheet.Cells
Range("N" & iterator).Select
Selection.Value = vlookup1String
End With
iterator = iterator + 1
End While
I'm getting an error # end while saying "expected if or select or sub..."
1) Have i made a syntax error?
2) Is my approach correct. I have observed this string approach to designing VLOOKUPS in vba only in one other place. It seemed best suited.
Fixing your code
You should use Wend not End While for your loop.
Cleaner Alternative
But you can fill an entire range in a single shot as below
It is better to "loop up" a range from the bottom using End(xlup) than to look down with End(xlDown) (which relies on no spaces)
You almost never need to use Select in VBA
Further explanation
rng1 sets a working range from the last used cell in column A in sheet datasheet to A3
rng1.Offset(0, Range("N1").Column - 1) says offset rng1 (which is column A) by 13 columns to use column N (ie OFFSET A by 14-1) for the formula insertion
I used the macro recorder to get the code you needed in column N for this part "=VLOOKUP(RC[-1],'GICS Sub-industry codes'!R2C1:R155C2,2,FALSE)".
IN R1C1 speak, RC[-1] means refer to the cell in the same row, but one column to the left. So in N3, the formula will start as =VLOOKUP(M4..), So in N30, the formula will start as `=VLOOKUP(M30..) etc
Suggested code
Sub QuickFill()
Dim ws As Worksheet
Dim rng1 As Range
Set ws = Sheets("datasheet")
Set rng1 = ws.Range(ws.[a3], ws.Cells(Rows.Count, "A").End(xlUp))
rng1.Offset(0, Range("N1").Column - 1).FormulaR1C1 = "=VLOOKUP(RC[-1],'GICS Sub-industry codes'!R2C1:R155C2,2,FALSE)"
End Sub

Resources