Excel VBA - Issue with sumproduct VBA script - vba

I am currently building a tool in order to take extracts from SAP and put them into a financial management tool (or Financial Tool). The tool successfully pulls actual data from a SAP CJ74 report, and normalizes the data.
I have a requirement to put a sumproduct function into a spreadsheet to extract data from a data source into the spreadsheet using names and dates as the product match. One sheet is for CAPEX spend, the other sheet is for OPEX spend. The two sheets are replicas of each other.
I attempted to write some code in order to execute my requirement below, but I am getting application defined or object defined error when executing the code. Could I get some assistance with either a better way of doing this, or correcting the errors below?
NOTE: the sheet where this code is running from is the 'Exporter tool'
Sub SumproductAlternative()
Dim Dim wb1 As Workbook, wb2 As Workbook, wb3 As Workbook
Dim Copyrange As Long, MaxRow As Long
Dim CapexPersonName As Range, CapexActualsDate As Range, CapexActualsCell As Range,
Dim OpexPersonName As Range, OpexActualsDate As Range, OpexActualsCell As Range
Dim OpexActualsDate As Range, CapexActualsDate as Range
Dim CapexPersonLookup As Range, OpexPersonLookup As Range
Set wb1 = Workbooks.Open("Financial Tool.xlsm")
Set wb2 = Workbooks.Open("Finance Extract.xlsm")
Set wb3 = Workbooks.Open("Exporter Tool.xlsm")
wb3.Worksheets("Config Sheet").Activate
Set CapexPersonName = ThisWorkbook.Sheets("Config Sheet").Range("A5:A" & LastRow)
Set CapexActualsDate = ThisWorkbook.Sheets("Config Sheet").Range("5:5" & LastColumn)
Set CapexSumRange = ThisWorkbook.Sheets("Capex Pivot").Range("A4").CurrentRegion
Set CapexPersonLookup = wb2.Sheets("Capex").Range("E2:E1300")
Set CapexActualsCell = wb2.Sheets("Capex").Range("5:5" & LastColumn)
Set OpexPersonName = ThisWorkbook.Sheets("Config Sheet").Range("A5:A" & LastRow)
Set OpexActualsDate = ThisWorkbook.Sheets("Config Sheet").Range("5:5" & LastColumn)
Set OpexSumRange = ThisWorkbook.Sheets("Capex Pivot").Range("A4").CurrentRegion
Set OpexPersonLookup = wb2.Sheets("Opex").Range("E2:E1300")
Set OpexActualsCell = wb2.Sheets("Opex").Range("c3:c" & LastRow)
wb1.Sheets("CAPEX").Select
With wb1.Sheets("Capex")
MaxRow = .Range("H528").CurrentRegion.rows.Count
For Copyrange = MaxRow To 528 Step -1
If .Cells(Copyrange).Interior.ColorIndex = 40 Then
.Cells(Copyrange).Formula = " = SUMPRODUCT((CapexPersonName" = "CapexPersonLookup)*(CapexActualsDate" = "CapexActualsCell),(CapexSumRange)"
End If
Next Copyrange
End With
MaxRow = 0
Copyrange = 0
wb1.Sheets("OPEX").Select
With wb1.Sheets("Opex")
MaxRow = .Range("H528").CurrentRegion.rows.Count
For Copyrange = MaxRow To 528 Step -1
If .Cells(Copyrange).Interior.ColorIndex = 40 Then
.Cells(Copyrange).Formula = " = SUMPRODUCT((OpexPersonName" = "OpexPersonLookup)*(OpexActualsDate" = "OpexActualsCell),(OpexSumRange)"
End If
Next Copyrange
End With

This bit concerns me:
Range("5:5" & LastColumn)
If you have say 4 for example as your last column, That range will be Rows 5 - 54 ALL COLUMNS because you are asking for "5:5" & 4 as a string that is "5:54", is this what you are expecting?
Also, where are LastRow and LastColumn being defined?

You assign formula in VBA in a form of string. So this code for example:
.Cells(Copyrange).Formula = "=SUMPRODUCT((CapexPersonName" = "CapexPersonLookup)*(CapexActualsDate" = "CapexActualsCell),(CapexSumRange)"
will error out since it is like a multiple Boolean expression (e.g. x = y = z) which is also not accepted in VBA.
To do what you want, try this:
Dim myformula As String
myformula = "=SUMPRODUCT((" & CapexPersonName.Address(, , , True) & "=" & _
CapexPersonLookup.Address(, , , True) & ")*(" & _
CapexActualsDate.Address(, , , True) & "=" & _
CapexActualsCell.Address(, , , True) & _
")," & CapexSumRange.Address(, , , True) & ")"
.Cells(Copyrange).Formula = myformula

Related

How To Have VBA Insert Formula Result as a Value

I got help last week getting my syntax and ranges correct, and thought I could just do a vlookup to finish it but apparently I was mistaken. It just seems like when I try to research how to accomplish this, I find various examples but I don't have the background to translate it to my code.
The macro runs and does almost everything its supposed to do. But in addition to inserting the arrays, there are 3 other cells that need values when there are blank cells in my ‘sourcerng’.
This is the logic for the cells that need values (the values are already in my worksheet, I just need to get them to these blank cells). I tried to do an IIF statement for these but I still have no idea what I'm doing. Would that be the best way? Should it just be another IF THEN statement?
rngBE - IF Column Z = 0 Then copy value from corresponding row in column O. Otherwise copy value from column Z
rngBG - IF Column AA = "Unknown" Then copy value from corresponding row in column I. Otherwise copy value from column AA.
rngBK - IF Column AB = "Unknown" Then copy value from corresponding row in column N. Otherwise copy value from column AB.
Sub AutomateAllTheThings6()
Dim arr3() As String
Dim arr11() As String
'Dim resBE As String
Dim rng3 As Range
Dim rng11 As Range
Dim rngBE As Range
Dim rngBG As Range
Dim rngBK As Range
Dim sourcerng As Range
'Dim firstRow As Long
Dim lastRow As Long
'Dim i As Long
Call OptimizeCode_Begin
'firstRow = 2
lastRow = ActiveSheet.Range("D1").End(xlDown).Row
Set rng3 = ActiveSheet.Range("BH2:BJ" & lastRow)
Set rng11 = ActiveSheet.Range("BL2:BV" & lastRow)
Set rngBE = ActiveSheet.Range("BE2:BE" & lastRow)
Set rngBG = ActiveSheet.Range("BG2:BG" & lastRow)
Set rngBK = ActiveSheet.Range("BK2:BK" & lastRow)
Set sourcerng = ActiveSheet.Range("BE2:BE" & lastRow)
arr3() = Split("UNKNOWN,UNKNOWN,UNKNOWN", ",")
arr11() = Split("UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,00/00/0000, _
00/00/0000,00/00/0000,00/00/0000,NEEDS REVIEW", ",")
For Each cell In sourcerng
If IsEmpty(cell) Then
Intersect(rng3, ActiveSheet.Rows(cell.Row)).Value = arr3
Intersect(rng11, ActiveSheet.Rows(cell.Row)).Value = arr11
'***PLS HELP***
Intersect(rngBE, ActiveSheet.Rows(cell.Row)).Value = "WEEEEE"
Intersect(rngBG, ActiveSheet.Rows(cell.Row)).Value = "WOOOOO"
Intersect(rngBK, ActiveSheet.Rows(cell.Row)).Value = "WAAAAA"
End If
Next
Range("BR2:BU2").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.NumberFormat = "mm/dd/yyyy"
Columns("BF:BF").Select
Selection.Delete Shift:=xlToLeft
Call OptimizeCode_End
End Sub
'*********TESTING***********
'resBE = IIf(Cells(13,Z).Value = 0, Cells(13,BE).Value = Cells(13,Z), Cells(13,BE).Value = Cells(13,O))
'***************************************
'For i = firstRow To lastRow
' valZ = Range("Z" & i)
' valOh = Range("O" & i)
'
' If valZ = 0 Then
' rngBE.Value = valOh
' Else rngBE.Value = valZ
' End If
There are several ways to do your task. If you're more of an "Excel" person than VBA you might consider this approach: You can inject the syntax of any "regular" formula in R1C1 Format.
So the formula mentioned above =if($Z2=0,$O2,$Z2) is .FORMULA format for any value in row 2.
But in .FORMULAR1C1 it can be inserted in ANY cell as: =IF(RC26=0,RC15,RC26) (basically no rows up or down, but always columns O (15) and Z(26).
So, your modified code would have something like this:
Intersect(rngBE, ActiveSheet.Rows(cell.Row)).FormulaR1C1 = "=IF(RC26=0,RC15,RC26)"
Intersect(rngBE, ActiveSheet.Rows(cell.Row)).Value = _
Intersect(rngBE, ActiveSheet.Rows(cell.Row)).Value
Again, this is NOT the most efficient way to accomplish your task, but if you're dealing with thousandsof rows, versus tens to hundreds of thousands, I wouldn't worry about it and it gives you a new tool to use.

Cross workbook Vlookup

Hey guys im trying to perform vlookup through cross-workbook. Im trying to write it this way.. but it seems not working using "x" and "x2"..
Folder = ActiveWorkbook.Path + "\"
Dim OptioneeManWb As Workbook
Dim TransOutWb As Workbook
Dim TransOutWs As Worksheet
Dim TermWb As Workbook
Dim TermWs As Worksheet
Set OptioneeManWb = Workbooks("optionee statement manual.xlsx")
Set TransOutWb = Workbooks.Open(Folder & "employee transfer out.xlsx")
Set x = TransOutWb.Worksheets("out").Range("A:C")
Set TermWb = Workbooks.Open(Folder & "employee terminated listing.xlsx")
Set x2 = TermWb.Worksheets("terminated").Range("A:C")
OptioneeManWb.Sheets("manual optionee stmt").Range("C6:C" & lastrow2).Formula = "=VLOOKUP(B:B,x,3,0)"
OptioneeManWb.Sheets("manual optionee stmt").Range("D6:D" & lastrow2).Formula = "=VLOOKUP(B:B,x2,3,0)"
OptioneeManWb.Sheets("manual optionee stmt").Range("C6:C" & lastrow2, "D6:D" & lastrow2).NumberFormat = "m/d/yyyy"
OptioneeManWb.Sheets("manual optionee stmt").Range("C:F").Copy
OptioneeManWb.Sheets("manual optionee stmt").Range("C:F").PasteSpecial xlPasteValues
TransOutWb.Close
TermWb.Close
VLOOKUP awaits an address of a range as second parameter.
.Formula = "=VLOOKUP(B:B," & x.Address(External:=True) & ",3,0)"
In your case "=VLOOKUP(B:B,x,3,0)" the x is not recognized as variable because it is within a string. Also you need to fill in the address in here (in external format so that the different workbook gets recognized too). Also see Range.Address Property (Excel) for info.
Also declare the variables to make sure the are of type range: Dim x As Range, x2 As Range at the top of your procedure.
OptioneeManWb.Sheets("manual optionee stmt").Range("C6:C" & lastrow2).Formula = "=VLOOKUP(B:B," & x.Address(External:=True) & ",3,0)"
OptioneeManWb.Sheets("manual optionee stmt").Range("D6:D" & lastrow2).Formula = "=VLOOKUP(B:B," & x2.Address(External:=True) & ",3,0)"
First You have to declare the variables x and x2 like this way :
Dim x as range
Dim x2 as range

VBA Problems with Concatenating String

I am trying to assign each of the ID's you see in column E and F of ws4 here...
...to the respective ID on my wsOutput in column K and L, respectively.
My code runs through without an Error but nothing happens. This is one of my first projects, so I apologize if this is straight-forward question.
I also consulted the Internet and found:
http://answers.microsoft.com/en-us/msoffice/forum/msoffice_excel-mso_windows8/how-to-concatenate-multiple-rows-by-the-condition/fdd048ba-5405-4e53-b463-125f9cde2c0c?auth=1
http://www.eileenslounge.com/viewtopic.php?f=27&t=12298
However, I wasn't able to get their approaches working.
Any help is greatly appreciated!
'Previous Code
'wsOutput -> Filter Sheet - Worksheet (TARGET) ; ws4 = Search Skills - Worksheet (SOURCE)
Dim separator As String, PreviousResultCG As String, NewResultCG As String, PreviousResultCategory As String, NewResultCategory As String
If separator = "" Then separator = " , "
'lRowInput = ws4.Range("A" & Rows.Count).End(xlUp).row - from above
lRowOutput = wsOutput.Range("A4:A" & Rows.Count).End(xlDown).row
With ws4
'For each ID on the Source-Worksheet
For Each ID In .Range("A2:A" & lRowInput)
'Find the respective ID on Target-Worksheet
Set FindID = wsOutput.Range("A4:A" & lRowOutput).Find(what:=ID, LookIn:=xlValues, lookat:=xlWhole)
'Get all CG ID's for the supplier and add them to previously found ID's of that supplier
If FindID = ID Then
PreviousResultCG = wsOutput.Range("K" & FindID.row).value
NewResultCG = PreviousResultCG & separator & .Range("E" & ID.row)
wsOutput.Range("K" & ID.row).value = NewResultCG
PreviousResultCategory = wsOutput.Range("L" & FindID.row).value
NewResultCategory = PreviousResultCategory & separator & .Range("F" & ID.row)
wsOutput.Range("L" & FindID.row).value = NewResultCategory
End If
Next ID
End With
Place source data in sheet named "source" and create another sheet where you want to lookup values from source data named as "target". Keep columns as you shown in images.
paste below mentioned code in module.
Sub look_values()
Dim id, source_id As Range
Dim data_row_num, id_row_num As Long
Dim source_sheet, target_sheet As Worksheet
Dim cg, cat As String
Set source_sheet = ThisWorkbook.Sheets("source")
Set target_sheet = ThisWorkbook.Sheets("target")
Set id = target_sheet.Range("A2")
Do Until id.Value = ""
source_sheet.Activate
Range("A1").Activate
Set source_id = Range("A:A").Find(what:=id.Value, LookIn:=xlValues, lookat:=xlWhole)
On Error Resume Next
cg = Cells(source_id.Row, 5).Value
On Error Resume Next
cat = Cells(source_id.Row, 6).Value
target_sheet.Activate
Cells(id.Row, 11).Value = cg
Cells(id.Row, 12).Value = cat
Set id = id.Offset(1, 0)
Loop
End Sub
Before running the macro, make sure that the format of ID column on both sheets are same. Will suggest you to First Clean & Trim the ID Column. Because it is visible in the image that ID column in target sheet has unrecognized characters.

Converting a long nested if and or formula into vba case

I have a nestled If And Or formula that I am trying to convert into probably a Case formula using VBA (or any other suggestion would be great), but I am a beginner and not sure how. The reason is that this formula currently is in every cell AG12:ACG500 and takes up so much memory that the spreadsheet is extremely slow.
Basically, I am trying to match the date in column Z12:Z500 (Outage Month Start) to the date in Row AG6:ACG6 (DATES), then looking in column C12:C500 (ACTV_NAME)... which provides the output of either R, S, L, MR, MS, ML, ?R, ?S or ?L in the cell where the two dates (column Z and row 6) intersect .. this should coincide with the where the Gantt Chart bar starts .. I do not need any help with the Gantt chart bars/color coding .. I just need help basically labeling them with the fore-mentioned.
=IF(OR($Z12="",$AA12=""),"",IF(AND(AG$6=$Z12,$Z12<>"",$C12="Relay",$L12="No"),"R",IF(AND(AG$6=$Z12,$Z12<>"",$C12="Substation",$L12="No"),"S",IF(AND(AG$6=$Z12,$Z12<>"",$C12="Line",$L12="No"),"L",IF(AND(AG$6=$Z12,$Z12<>"",$C12="Relay",$L12="YES"),"MR",IF(AND(AG$6=$Z12,$Z12<>"",$C12="Substation",$L12="YES"),"MS",IF(AND($AF$6=$Z12,$Z12<>"",$C12="Line",$L12="YES"),"ML",IF(AND(AG$6=$Z12,$Z12<>"",$C12="Relay",$L12="Maybe"),"?R",IF(AND(AG$6=$Z12,$Z12<>"",$C12="Substation",$L12="Maybe"),"?S",IF(AND($AF$6=$Z12,$Z12<>"",$C12="Line",$L12="Maybe"),"?L",""))))))))))
Your formula can be simplified to:
=IF(OR($Z12="",$AA12=""),"",IF(AND(AG$6=$Z12,$Z12<>""),IF($L12 = "YES","M" & LEFT($C12,1),IF($L12 = "Maybe","?" & LEFT($C12,1),LEFT($C12,1))),""))
Converting single formula into a routine that loops
This is Scott Craner's simplified version of your formula, converted into a routine that will loop through all the cells in AG12:ACG500 and check each cell for their intersecting criteria.
I am not able to test this code because I have no data set to base it off of. That being said, I'm not sure that it will perform in the way you desire. Let me know if it works for you.
Sub compareDates()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets(1)
Dim dataRange As Range: Set dataRange = ws.Range("AG12:ACG500")
Dim oMS As Range, aN As Range, idk As Range, d As Range
Dim yNM As Range, myCell As Range, myRow As Long, myCol As Long
For Each myCell In dataRange
myRow = myCell.Row
myCol = myCell.Column
Set oMS = ws.Range("Z" & myRow) 'Outage Month Start
Set aN = ws.Range("C" & myRow) 'ACTV_NAME
Set idk = ws.Range("AA" & myRow) 'not sure what AA is for
Set d = ws.Cells(6, myCol) 'DATES
Set yNM = ws.Range("L" & myRow) 'yes no maybe
If oMS.Value = "" Or idk.Value = "" Then
myCell.Value = ""
ElseIf d.Value = oMS.Value And oMS.Value <> "" Then
If UCase(yNM.Value) = UCase("Yes") Then
myCell.Value = "M" & Left(aN.Value, 1)
ElseIf UCase(yNM.Value) = UCase("Maybe") Then
myCell.Value = "?" & Left(aN.Value, 1)
Else: myCell.Value = Left(aN.Value, 1)
End If
Else: myCell.Value = ""
End If
Next myCell
End Sub

Search for two values and copy everything in between in a loop

I have a worksheet which has many terms in Column A.I want to search for two terms for example
term A and term B and copy all rows between the two terms and paste it into a new sheet.These two terms may repeat in the column. The problem which I am basically facing the following problem : whenever I run my code it also copies rows between term B and term A which is unnecessary. Following is the code i am using for two terms term A and term B.
For example my column A is
Institute
Event
Job
Computer
Laptop
Figures
Event
figures
format
computer
and many more terms
I want to copy all the rows between term A: Event and term B: Laptop and paste it into a new sheet. What my code is doing is it is copying the rows between all combinations of Event and computer. Even the rows between computer and event are copied(in this case Figure and laptop).
Sub OpenHTMLpage_SearchIt()
Dim Cell As Range, Keyword$, N%, SearchAgain As VbMsgBoxResult
Dim ass As Variant
Dim Cellev As Range, prakash$, P%, SearchAgaina As VbMsgBoxResult
Dim asa As Variant
StartSearch:
N = 1
Keyword = "Event"
If Keyword = Empty Then GoTo StartSearch
For Each Cell In Range("A1:A500")
If Cell Like "*" & Keyword & "*" Then
ass = Cell.Address
P = 1
prakash = "Computer"
If prakash = Empty Then GoTo StartSearch
For Each Cellev In Range("A1:A500")
If Cellev Like "*" & prakash & "*" Then
asa = Cellev.Address
Range(asa, ass).Select
Selection.Copy
Sheets.Add After:=Sheets(Sheets.Count)
Range("B13").Select
ActiveSheet.Paste
Worksheets("sheet1").Select
P = P + 1
End If
Next Cellev
N = N + 1
End If
Next Cell
End Sub
Edit: code formatting.
The following is the code which is working for me.This copies everything in between Event and laptop and pastes it into a new sheet. Then again it searches for a second time and this time the search will start from the next row to the first search.I hope I am clear with this.
Sub Star123()
Dim rownum As Long
Dim colnum As Long
Dim startrow As Long
Dim endrow As Long
Dim lastrow As Long
rownum = 1
colnum = 1
lastrow = Worksheets("Startsheet").Range("A65536").End(xlUp).Row
With ActiveWorkbook.Worksheets("StartSheet").Range("a1:a" & lastrow)
For rownum = 1 To lastrow
Do
If .Cells(rownum, 1).Value = "Event" Then
startrow = rownum
End If
rownum = rownum + 1
If (rownum > lastrow) Then Exit For
Loop Until .Cells(rownum, 1).Value = "Laptop"
endrow = rownum
rownum = rownum + 1
Worksheets("StartSheet").Range(startrow & ":" & endrow).Copy
Sheets("Result").Select
Range("A1").Select
ActiveSheet.Paste
Next rownum
End With
End Sub
Try this:
Sub DoEeeeeet(sheetName, termA, termB)
Dim foundA As Range, _
foundB As Range
Dim newSht As Worksheet
With Sheets(sheetName).Columns(1)
Set foundA = .Find(termA)
If Not foundA Is Nothing Then
Set foundB = .Find(termB, after:=foundA, searchdirection:=xlPrevious)
End If
End With
If foundA Is Nothing Or foundB Is Nothing Then
MsgBox "Couldn't find " & IIf(foundA Is Nothing, termA, termB)
Else
Range(foundA, foundB).Copy
Set newSht = Sheets.Add
newSht.Range("B13").PasteSpecial
End If
End Sub
You can call it as follows:
DoEeeeeet "Sheet1","Event","Laptop"
It'll find the first instance of "Event" and the last instance of "Laptop" on the sheet named "Sheet1" and copy all of that data to B13 and subsequent cells in a new sheet.
Is that what you want? Or do you want each of the subranges beginning with "Event" and ending with "Laptop"?