Why is my VBA SUMIFS function returning zeros? - excel

First, allow me to thank you for any help you are able to lend me. I appreciate it! (:
My issue is this: I have two workbooks, one with raw data, and one in which the raw data is consolidated into relevant statistics. I am trying to SUMIFS the data in X:X in my raw data workbook (6620) by two criteria in the results book and then update the value in the corresponding cell in the results book.
The problem is that the macro returns all zeros. I have double checked the data types, names, ranges, etc, but no luck. Leaving me to think there is something wonky in my code.
I include two photos at the end of this post of example raw data and results tables so you can see what I am working from.
Sub ImportFTEs()
Application.ScreenUpdating = False
Application.EnableEvents = False
Dim ws As Integer
Workbooks.Open Filename:=ActiveWorkbook.Path & "\6620\FY19*.xlsb"
For ws = 1 To Worksheets.Count
Sheets(ws).Name = "Sheet1"
Next ws
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim l As Integer
Dim totalFTE As Long
Dim lastRow As Integer
lastRow = Cells(Rows.Count, "D").End(xlUp).Row
Dim wb_a As Worksheet
Set wb_a = Workbooks.Open(ActiveWorkbook.Path & "\FY19*.xlsb").Sheets("Sheet1")
Dim wb_b As Worksheet
Set wb_b = ThisWorkbook.Sheets("B")
Dim sumRange As Range
Set sumRange = wb_a.Range("X:X")
Dim cRange1 As Range
Set cRange1 = wb_a.Range("D:D")
Dim criteria1 As Range
Dim cRange2 As Range
Set cRange2 = wb_a.Range("S:S")
Dim criteria2 As Range
For k = 8 To 18
For l = 7 To 18
For i = 7 To 18
Set criteria1 = wb_b.Cells(7, i)
For j = 8 To 18
Set criteria2 = wb_b.Cells(j, 6)
wb_b.Cells(k, l).value = Application.WorksheetFunction.SumIfs(sumRange, cRange1, criteria1, cRange2, criteria2)
Next j
Next i
Next l
Next k
ActiveWorkbook.Close savechanges:=True
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub

You don't need so many nested loops. Your original code is looping through every possible criteria for each k and l. Assuming wb_b.Cells(k, l) is supposed to be a reference to the cell intersected by your month column and employee name row, you could use your i and j values.
For i = 7 To 18
Set Criteria1 = wb_b.Cells(7, i)
For j = 8 To 18
Set Criteria2 = wb_b.Cells(j, 6)
wb_b.Cells(j, i).Value = Application.WorksheetFunction.SumIfs(sumRange, cRange1, Criteria1, cRange2, Criteria2)
Next j
Next i

Related

Convert Excel Array formula into VBA code

I have two set of range named as LIST_KEY and LIST_CAT. In Column A, user will add some data which will contain one of the one of the text from LIST_KEY. I would like to get corresponding Category list from LIST_CAT depends upon the Key value
I am using below VBA code to achieve this. This include a Array formula.
Sub match()
Dim ss As Workbook
Dim test As Worksheet
Set ss = Excel.Workbooks("test.xlsm")
Set test = ss.Worksheets("Sheet1")
For i = 2 To test.Cells(Rows.Count, "A").End(xlUp).Row
Cells(i, "B").FormulaArray = "=INDEX(LIST_CAT,MATCH(TRUE,ISNUMBER(SEARCH(LIST_KEY,RC[-1])),0))"
Cells(i, "B").Formula = Cells(i, "B").Value
Next i
End Sub
This code works perfect if there is less data to fetch. But in my original use case, I will have around 8000 rows. Due to this large number of columns excel will go to not responding state after 2-3 minutes.
Instead of adding Array formula to column B, Is there anyway to convert that into VBA to run this faster. Sorry, I am new to this VBA stuff and dont have much experience
Try the following code, which uses arrays instead of worksheet formulas...
Option Explicit
Sub GetCategories()
Dim sourceWorkbook As Workbook
Set sourceWorkbook = Workbooks("test.xlsm")
Dim sourceWorksheet As Worksheet
Set sourceWorksheet = sourceWorkbook.Worksheets("Sheet1")
Dim lookupArray As Variant
lookupArray = sourceWorkbook.Names("LIST_KEY").RefersToRange.Value
Dim returnArray As Variant
returnArray = sourceWorkbook.Names("LIST_CAT").RefersToRange.Value
Dim tableArray As Variant
Dim lastRow As Long
With sourceWorksheet
lastRow = .Cells(.Rows.Count, "a").End(xlUp).Row
tableArray = .Range("A2:B" & lastRow).Value
End With
Dim desc As String
Dim i As Long
Dim j As Long
For i = LBound(tableArray, 1) To UBound(tableArray, 1)
desc = tableArray(i, 1)
For j = LBound(lookupArray, 1) To UBound(lookupArray, 1)
If InStr(1, desc, lookupArray(j, 1), vbTextCompare) > 0 Then
tableArray(i, 2) = returnArray(j, 1)
Exit For
End If
Next j
Next i
sourceWorksheet.Range("B2").Resize(UBound(tableArray, 1), 1).Value = Application.Index(tableArray, 0, 2)
End Sub

Worksheet function Sum-if causing error type mismatch

I am looping through the worksheets to sumif the amounts that are "C" and "D".
Each tabs have the amounts in column M and whether they are credit or debit in column N, indicated by the letter C or D.
First I am putting the letters C and D on blank cells and trying to sumif these two amounts next to them.
I am getting a type mismatch error at the sumif line and the whole line is highlighted.
At first I thought maybe it was ws = Worksheets(I) causing the problem so I swapped them out with Worksheets(I), but it still did not work.
Sub Sumiftabs()
Dim Filepath As String
Dim UIGFile As Workbook
Dim Column As String
Dim Month As String
Dim Year As Integer
Dim I As Long
Dim TY As Integer
Dim TYLetter As String
Dim T As Long
Dim TreatyYear As Long
Dim WS_Count As Integer
Dim ws As Worksheet
Application.ScreenUpdating = False
TreatyYear = Sheets("Control").Range("B7").Value
'On Error Resume Next
For T = TreatyYear To 16 Step -1
TYLetter = WorksheetFunction.VLookup(T, Workbooks("Separate tabs.xlsm").Sheets("Control").Range("H:I"), 2, False)
TY = Sheets("Control").Range("B7").Value
Month = Sheets("Control").Range("B5").Value
Year = Sheets("Control").Range("B4").Value
Filepath = Sheets("Control").Range("B2").Value
Set UIGFile = Workbooks.Open("K:\Ayoon\UIG\" & Year & "\" & Month & "\UIG_NSA_MonYear_TY" & T & ".xls")
WS_Count = UIGFile.Worksheets.Count
For I = WS_Count To 1 Step -1
Set ws = Worksheets(I)
'Direct Premium
UIGFile.Worksheets(I).Range("S4").Value = "C"
UIGFile.Worksheets(I).Range("S5").Value = "D"
UIGFile.Worksheets(I).Range("T4").Value = _
Application.WorksheetFunction.SumIf(ws.Range("N:N"), ws.Range("S:S"), ws.Range("M:M"))
UIGFile.Worksheets(I).Range("T5").Value = _
Application.WorksheetFunction.SumIf(ws.Range("N:N"), ws.Range("S:S"), ws.Range("M:M"))
Next I
UIGFile.Close savechanges:=True
Next T
Application.ScreenUpdating = True
End Sub
Your SUMIF looks incorrect.
Eg try this instead:
UIGFile.Worksheets(I).Range("T4").Value = _
Application.WorksheetFunction.SumIf(ws.Range("N:N"), "C", ws.Range("M:M"))

Excel VBA Makro compare and copy

I need to copy a row from a sheet into a third sheet, if the ServerID exists in both sheets
Sub XDDXH()
Dim i As Integer
Dim z As Integer
Dim j As Integer
For i = 2 To 3318
For z = 8 To 731
If Worksheets("Sheet1").Range(i, 1).Value = Worksheets("Sheet2").Range(z, 8).Value Then
Worksheets("Sheet1").Range("i:i").Copy Destination:=Worksheets("Sheet3").Range("j:j")
j = j + 1
End If
Next z
Next i
End Sub
With this code I get runtime error 1004.
This is my first time working with VBA.
This can be simplified to one loop with CountIf (untested, but I think I got everything). You could also use Match if you prefer that.
Sub XDDXH()
Dim lookInRng as Range
Set lookInRng = Worksheets("Sheet2").Range("H8:H731")
Dim sourceRng as Range
Set sourceRng = Worksheets("Sheet1").Range("A2:A3318")
Dim rng as Range
For Each rng in sourceRng
If Application.CountIf(lookInRng, rng.Value) > 0 Then
Dim j as Long
j = j + 1
rng.EntireRow.Copy Destination:=Worksheets("Sheet3").Range("A" & j)
End If
Next rng
End Sub
Will implement a couple changes and consolidate the general consensus from comments:
'"As Integer" will get silently converted to "As Long" so just start with Long to save processing power
Dim i As Long, j as long, z as long
Dim ws1 as Worksheet, ws2 as Worksheet, ws3 as Worksheet
'setting sheets to just be cleaner and easier to write
set ws1 = Sheets(1) 'using the index, but could be Sheets("sheet1"), etc.
set ws2 = sheets(2)
set ws3 = sheets(3)
j = 1 'need this or you'll default to j=0 which doesn't work for a range in excel
For i = 2 To 3318
For z = 8 To 731
If ws1.Cells(i, 1).Value = ws2.Cells(z, 8).Value Then
ws1.Rows(i).Copy Destination:=ws3.Rows(j)
j = j + 1
End If
Next z
Next i
Note that Range("A1") and Cells(1,1) are syntactically different ways of saying the same thing. Be careful to not interchange those.
If utilizing a variable, you do not use quotations, e.g., variable j is iterated on a new sheet and you wouldn't write Range("j:j") as that will be the whole column 'J in the worksheet (yes, lowercase doesn't technically matter for that).

Why am I receiving Error 1004 when trying to specify the loop variable in a cell reference?

I am stuck, primarily because I am still brand spanking new at VBA. As such, I really appreciate any help you can lend me. I have looked through many other Error 1004 posts on here, but they were either for different issues, or it is quite possible that I am just too ignorant to know what to do with the advice in them.
My issue is this: I have two workbooks, one with raw data, and one in which the raw data is consolidated into relevant statistics. I am trying to sumif the data in X:X in my raw workbook (6620) by two criteria in the statistics book and then update the value in the corresponding cell in the statistics book.
I am running into a Run-time Error 1004: Application-defined or object-defined error at the indicated points. I am lost as to how to move past this.
Any help is greatly appreciated!
This is as far as I have gotten:
Option Explicit
Sub ImportFTEs()
Application.ScreenUpdating = False
Application.EnableEvents = False
Dim ws As Integer
Workbooks.Open Filename:=ActiveWorkbook.Path & "\6620\FY19*.xlsb"
For ws = 1 To Worksheets.Count
Sheets(ws).Name = "Sheet1"
Next ws
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim l As Integer
Dim totalFTE As Long
Dim lastRow As Integer
lastRow = Cells(Rows.Count, "D").End(xlUp).Row
Dim wb As Worksheet
Set wb = Workbooks.Open(ActiveWorkbook.Path & "\FY19*.xlsb").Sheets("Sheet1")
Dim wc As Worksheet
Set wc = ThisWorkbook.Sheets("B")
Dim sum1R As Range
Set sum1R = wb.Range("X:X")
Dim arg2R As Range
Set arg2R = wb.Range("D:D")
Dim arg2C As Range
Set arg2C = wc.Cells(7, i)
>>> Error 1004
Dim arg3R As Range
Set arg3R = wb.Range("S:S")
Dim arg3C As Range
Set arg3C = wc.Cells(j, 6)
>>> Error 1004
For k = 8 To 18
For l = 7 To 18
For i = 7 To 18
For j = 8 To 18
wc.Cells(k, l).value = Application.WorksheetFunction.SumIfs(sum1R, arg2R, arg2C, arg3R, arg3C)
Next j
Next i
Next l
Next k
ActiveWorkbook.Close savechanges:=True
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
Should be something like this - you need the Set lines containing i and j inside their respective loops - that way the values actually increment (and aren't 0 when they're initialized):
Option Explicit
Sub ImportFTEs()
Application.ScreenUpdating = False
Application.EnableEvents = False
Workbooks.Open Filename:=ActiveWorkbook.Path & "\6620\FY19*.xlsb"
Dim i As Long, j As Long, k As Long, l As Long
Dim totalFTE As Long
Dim wb As Worksheet
Set wb = Workbooks.Open(ActiveWorkbook.Path & "\FY19*.xlsb").Sheets("Sheet1")
Dim wc As Worksheet
Set wc = ThisWorkbook.Sheets("B")
Dim sum1R As Range
Set sum1R = wb.Range("X:X")
Dim arg2R As Range
Set arg2R = wb.Range("D:D")
Dim arg3R As Range
Set arg3R = wb.Range("S:S")
Dim arg2C As Range
Dim arg3C As Range
For k = 8 To 18
For l = 7 To 18
For i = 7 To 18
Set arg2C = wc.Cells(7, i)
For j = 8 To 18
Set arg3C = wc.Cells(j, 6)
wc.Cells(k, l).Value = Application.WorksheetFunction.SumIfs(sum1R, arg2R, arg2C, arg3R, arg3C)
Next j
Next i
Next l
Next k
ActiveWorkbook.Close True
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub

Excel 2013 Overflow due to lack of VBA optimization

I would like to export data from a consolidated sheet (DATA) to multiple sheets regarding criteria.
I have a total of 13 criteria, each criteria has to be exported in its dedicated sheet.
I'm trying to optimize this macro (only 2 criteria here) because it lag out
Sub copy()
Application.ScreenUpdating = False
Dim i As Long
Dim j As Long
Dim sh As Worksheet
Dim feuillePrincipale As Worksheet
Dim S01Sheet As Worksheet
Dim S02Sheet As Worksheet
Set feuillePrincipale = ThisWorkbook.Sheets("DATA")
Set S01Sheet = ThisWorkbook.Sheets("S01")
Set S02Sheet = ThisWorkbook.Sheets("S02")
For Each sh In ThisWorkbook.Worksheets
If sh.Name = "S01" Then
i = 2
j = 2
While Not IsEmpty(feuillePrincipale.Cells(i, 1))
If feuillePrincipale.Cells(i, 11).Value Like "S01*" Then
feuillePrincipale.Cells.Rows(i).EntireRow.copy S01Sheet.Rows(j)
j = j + 1
End If
i = i + 1
Wend
End If
If sh.Name = "S02" Then
i = 2
j = 2
While Not IsEmpty(feuillePrincipale.Cells(i, 1))
If feuillePrincipale.Cells(i, 11).Value Like "S02*" Then
feuillePrincipale.Cells.Rows(i).EntireRow.copy S02Sheet.Rows(j)
j = j + 1
End If
i = i + 1
Wend
End If
Next
Application.ScreenUpdating = True
End Sub
If you have any idea, I read I can use Advanced filter but as you guess I'm new in VBA so I'm listening any tips!
Here is the Advanced Filter method you asked for:
Public Sub Christophe()
Const FILTER_COLUMN = 11
Dim i&, rCrit As Range, rData As Range, aShts
aShts = ["SO"&row(1:13)]
Set rData = Sheets("DATA").[a1].CurrentRegion
Set rCrit = rData.Resize(2, 1).Offset(, rData.Columns.Count + 2)
rCrit(1) = rData(1, FILTER_COLUMN)
For i = 1 To UBound(aShts)
rCrit(2) = aShts(i, 1) & "*"
rData.AdvancedFilter xlFilterCopy, rCrit, Sheets(aShts(i, 1)).[a1].Resize(, rData.Columns.Count)
Next
rCrit.Clear
End Sub
The execution time should be instantaneous.
Note: this assumes that you do have 13 criteria, each starting with "SO" and that they occupy column 11 of the Data sheet. It also assumes that you already have 13 sheets named SO1... SO13 in the workbook.
UPDATE
Based on new information that the pattern of the criteria can change, please try this version instead. Note, that it assumes that the sheets already exist and that the sheet names match the criteria:
Public Sub Christophe()
Const FILTER_COLUMN = 11
Dim i&, rCrit As Range, rData As Range, aShts
aShts = Array("SO1", "SO2", "ADQ03", "LocS10")
Set rData = Sheets("DATA").[a1].CurrentRegion
Set rCrit = rData.Resize(2, 1).Offset(, rData.Columns.Count + 2)
rCrit(1) = rData(1, FILTER_COLUMN)
For i = 0 To UBound(aShts)
rCrit(2) = aShts(i) & "*"
rData.AdvancedFilter xlFilterCopy, rCrit, Sheets(aShts(i)).[a1].Resize(, rData.Columns.Count)
Next
rCrit.Clear
End Sub
Try using an array to set your criteria sheets:
Dim shArray As Variant
Dim shArrayString As String
Dim feuillePrincipale As Excel.Worksheet
Dim i As Long
Dim j As Long
Set feuillePrincipale = ThisWorkbook.Sheets("DATA")
j = 1
'// Create array and populate
shArray = Array("S01", "S02", "S03", "S04") '// add as required
'// Create string representation of array
shArrayString = "{"""
For i = LBound(shArray) To UBound(shArray)
shArrayString = shArrayString & shArray(i) & ""","""
Next
shArrayString = Left(shArrayString, Len(shArrayString) - 2) & "}"
'//Start loop
With feuillePrincipale
For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
If Not Evaluate("ISERROR(MATCH(" & Left(.Cells(i, 11), 3) & "," & shArrayString & ",0))") Then
.Rows(i).Copy Sheets(shArray(WorksheetFunction.Match(Left(.Cells(i, 11), 3), shArray, 0))).Cells(j, 1)
j = j + 1
End If
Next
End With
It's a bit unclear because if you follow the code you've posted - it's actually just copying and pasting data to the same sheet...
Yes, you should use an autofilter and use a special select to get only the visible cells.
If you want the loop method, you should loop through each row on sheets("DATA") and use a Select Case Statement to decide onto which sheet the data is placed.
By looping through each sheet you are adding loops that will slow it down.
Application.ScreenUpdating = False
Dim i As Long
Dim j As Long
Dim cel As Range
Dim sh As Worksheet
Dim feuillePrincipale As Worksheet
Dim S01Sheet As Worksheet
Dim S02Sheet As Worksheet
Set feuillePrincipale = ThisWorkbook.Sheets("DATA")
Set S01Sheet = ThisWorkbook.Sheets("S01")
Set S02Sheet = ThisWorkbook.Sheets("S02")
For Each cel In feuillePrincipale.Range(feuillePrincipale.Range("A1"), feuillePrincipale.Range("A1").End(xlDown))
Select Case Left(cel.offset(,10).value, 3)
Case "S01"
j = S01Sheet.Range("A" & Rows.count).End(xlUp).Offset(1).Row
feuillePrincipale.Cells.Rows(cel.Row).EntireRow.copy S01Sheet.Rows(j)
Case "S02"
j = S02Sheet.Range("A" & Rows.count).End(xlUp).Offset(1).Row
feuillePrincipale.Cells.Rows(cel.Row).EntireRow.copy S02Sheet.Rows(j)
'Case .... keep adding select statement till you get to the last condition
Case Else
End Select
Next cel
Application.ScreenUpdating = True

Resources