Sumif loop through data groups vba - excel

If this is answered elsewhere please advise...
I am trying to come up with a sumif that will sum column D if Column A criteria = "PL211010" & "PL203000". The problem is that I need the macro to sum by groups rather than the whole sheet (see pic)
Not sure where to even start, should i be using a For Next loop? or is a loop even necessary?
Important note This pivot dynamically changes month to month. The accounts are not static, they can either increase or decrease. So placing a static formula will not work...
The code below is my attempt to get this to work, just trying to give a baseline.
Dim nRowMax, nRowNow As Integer
Application.ScreenUpdating = False
Cells(4, 1).Select
Selection.End(xlDown).Select
nRowMax = Selection.Row
For i = nRowMax To 4 Step -1
If Left(Cells(i, 1), 8) = "PL211010" & "PL203000" Then
WorksheetFunction.SumIf (Cells(i, 4))
End If
Next i
Application.ScreenUpdating = True

This can be done without VBA by writing formulas directly on the datasource as #ashleedawg stated, and that would probably be your easiest option, or by writing them directly off the pivot. I have done a mock-up example below that will work for the case you provided:
Here's a screenshot:
Change the Pivot Table Layout as I have instructed in the picture in cell D1
Use the formula in cell H4: =SUM(SUMIFS($F$4:$F$11,$D$4:$D$11,D4,$E$4:$E$11,{"A","B"}))
Drag down as needed.
Now, it's late for me and I did this quick, so I realize it's repetitive and a bit messy. For that you can simply organize a list of single elements and write the formulas off that list.
Alternatively, you can write the formulas directly off the data source by modifying the range arguments of the formula I provided.

Related

VBA Transpose From Specific Number of Cells Above

I've been working on a VBA code, this is only a minor part of my project for reviewing accounting transactions.
The code not included inserts blank rows where there have been transactions using multiple account names. I want to transpose the multiple account names on each transactions where necessary. The "RowNum" code references the number count of account names on that particular transaction. I was hoping to insert that number into my FormulaR1C1.
Sub cellnum()
RowNum = "=R[-1]C[4]"
Application.CutCopyMode = False
ActiveCell.FormulaR1C1 = "=transpose(R[-" & RowNum.Value & "C[-1]:R[-1]C[-1])"
End Sub
If you want to put the formula in a different cell than the active cell you need to set the range for that cell first.
for example something like should give the right result
Set rng = Range("A1")
rng.FormulaR1C1 = "=transpose(R[-" & RowNum.Value & "C[-1]:R[-1]C[-1])"
Im new to VBA and still learning but I think this is the way to go.

Repeating Formula with Incrementing Cell Reference

So I have built a formula that has Absolute Cell References, and wanted to repeat the same formula down 3000 cells with each one referencing increment cells. (1st formula referring to Cell $A$1, 2nd formula referring to $A$2) I know that I could easily do this without referencing exact cells and the Fill Handle and this is currently how it's set up, however there's a very large number of people who work in this spreadsheet that have bad Excel manners, and regularly delete rows and cells or copy and paste, which breaks the formulas.
Rather than manually editing the same formula in each cell to change the references from relative to absolute, I was wanting to run a Macro to automatically run the formula for 3000 cells.
I had at first built a Macro that fills 20 cells with the formula, but it didn't adjust the formula based on the active cell. (Always entered with range $A$1:$A$20, and not $A$21:$a$40 when started further down) I changed the Macro to loop, but it looks with all formulas referencing $A$1 rather than updating.
The Macro set up to loop is as follows:
Sub HDDatesRef()
ActiveCell.Select
ActiveCell.FormulaR1C1 = "=IF(AND(HD!R1C1>0,ISBLANK(HD!R1C4)),HD!R1C1,""n/a"")"
ActiveCell.Offset(1, 0).Range("A1").Select
Loop Until ActiveCell.Value = ""
End Sub
Any and all help with figuring this out would help immensely. Right now I also have access to Liknedin Learning, so if there's any suggestions for courses on there I should look into so I can understand what I need to do will help with this.
The Excel application object has a function called ConvertFormula which you can use to change a formula between reference styles (A1 or R1C1) and to specify whether the rows and columns should be relative references or absolute references.
If you start off by creating the formula in each row as a relative reference then you can use ConvertFormula to turn it into an absolute reference. The only restriction is that the formula cannot be longer than 255 characters.
Adapting your code and following the advice in How to avoid using Select in Excel VBA gives us:
Option Explicit
Sub HDDatesRef()
Dim r As Range
' If we know the cell address we want to start in then we could use that directly
' e.g. Set r = Worksheets("HD").Range("E1")
Set r = ActiveCell
Do
' The With block just saves us typing r.FormulaR1C1 multiple times
With r
' Don't know what your relative formula would be. I've assumed that we are
' working in column E but adjust as appropriate
.FormulaR1C1 = "=IF(AND(HD!RC[-4]>0,ISBLANK(HD!RC[-1])),HD!RC[-4],""n/a"")"
' Take the formula we already have which is in R1C1 format, keep it in R1C1 format,
' change it from a relative reference based on cell r to an absolute reference
' and make that the new formula for this cell
.FormulaR1C1 = Application.ConvertFormula(.FormulaR1C1, xlR1C1, xlR1C1, xlAbsolute, r)
End With
' Move down one row
Set r = r.Offset(1, 0)
Loop Until r.Value = ""
End Sub
In case you aren't familiar with them. here are the references for Option Explicit and With...End With
You can do this without looping, Excel is smart enough to know you want incremental.
As an example do run this on a fresh sheet:
Sub ShowIncremental()
Range("A1:A10").Formula = "=Row(A1)"
Range("B1:B10").Formula = "=A1*2"
Range("C1:C10").Formula = "=sum(B$1:B1)"
End Sub
Notice the formulas created in A1:C10. Notice Excel incremented them even though the code didn't say to except in the case where we absoluted B$1.
I recommend you do something similar with your code to avoid looping, this will be much much faster.

How to refactor comparison loops in my excel vba code for speed?

I am new to Excel VBA and do not have much experience. I have two worksheets of data that I compare and then if a value matches up I copy and paste it to the second worksheet. I use for loops to compare every row and was wondering if there is a better way to do this? I am using brute force currently and was hoping there would be a way so that my program will not run for very long. (I repeat this block of code on different sheets 13 times). Essentially this code is consolidating information if it meets certain conditions. Below is my code.
Sub consolidate(z)
Sheets(z).Range("B1:AXH100").Delete '''deletes former values'''
For i = 1 To 30
For x = 1 To 500
If IsEmpty(Sheets("Sheet1").Cells(x, 13)) Then 'if cell value is empty skip it'
a = 1
Else:
If Sheets("Sheet1").Cells(x, 18) = Sheets(z).Cells(1, 1) Then 'check to see if value is same'
If Sheets("Sheet1").Cells(x, 13) = Sheets(z).Cells(i, 1) Then 'check to see if value is same'
Sheets("Sheet1").Cells(x, 15).Copy 'copy value'
Sheets(z).Select 'select second sheet'
Cells(i, 1).Select
ActiveSheet.Cells(ActiveCell.Row, Columns.Count).End(xlToLeft).Offset(0, 1).Select 'offsets cell to the
left'
Selection.PasteSpecial past:=xlPasteValues 'pastes'
End Sub
As I answered here, if you need to access or change several cells, you're much better off reading the cells into an array, working directly with the array(s) and sending the results back to Excel once you're done. It's quite a bit more work, and Excel's array-handling is not the best, but speed-wise there's no comparison.
This article explains the process in more detail.

Performance of deleting many rows from an autofilter in VBA

I would like to know if there is a faster way do this than the code I am using. I got the code using xlUp from the recorder.
rCnt = Cells(Rows.Count, "B").End(xlUp).Row
ActiveSheet.Range("$B$1:$J" & rCnt).AutoFilter Field:=5, _
Criteria1:=Application.Transpose(arrCodes), Operator:=xlFilterValues
Rows("2:" & rCnt).Delete Shift:=xlUp
And actually, if there was some way to flip the filter, I wouldn't need to delete at all as this is a temporary table that I copy from. However, all my research has failed to find a way to do
Criteria1:=Application.Transpose(<>arrCodes)
and arrCodes has too many elements to list in the filter. And the stuff that is not in arrCodes is way too numerous to make an array from. Thanks.
If you want to just use Excel UI and not formulas or VBA, you can do the following simple steps to get an "inverse" filter. This could then be ported to VBA if needed:
Apply the filter with the opposite conditions
Color those cells in one column (either font or background)
Clear the filter
Filter again but this time by cells in that column without color
Copy those results where you want them
This will not work well if the column already has some background colors. If that is the case, you can add a new column and color it. If this is in VBA, you could automate those steps. There are limits, but this is quick and simple if it applies.
I've had success in the past with building then deleting a range. You can combine ranges with Union(). I've attached a bit of example code, it's not wonderful but it shows the basic concept. This example deletes rows with odd numbers in column A in rows 2 through 11.
Public Sub DeleteRows()
Dim deleteThis As Range
For i = 2 To 11
If Sheet1.Cells(i, 1).Value Mod 2 = 1 Then
If deleteThis Is Nothing Then
Set deleteThis = Sheet1.Rows(i)
Else
Set deleteThis = Union(deleteThis, Sheet1.Rows(i))
End If
End If
Next i
deleteThis.Delete xlShiftUp
End Sub

Excel-VBA Comparing Column Data

I am completely new to Excel VBA, and I need to write code to do a simple task. I need to compare values in two different columns row by row, and see if the difference exceeds 50. If so, I need to highlight the entire row.
I program in other languages, so I have a basic understanding for how this works, but I have no clue how to navigate cells/view the content inside the cells. I tried this but it didn't work out (it would just highlight every single row). I simplified it to compare if values are equal or not, but to no avail (still everything is highlighted) Can anyone give me some help?
Dim strF0_col As Integer, sF0_col As Integer
Dim myRow, counter As Integer
Dim rEnd As Integer
Sub compare_F0()
rEnd = 100
strF0_col = 307
sF0_col = 317
counter = 0
For myRow = 2 To rEnd Step 1
Application.StatusBar = counter & "rows highlighted."
If (Cells(myRow, strF0_col).Value = Cells(myRow, sF0_col).Value) Then
Cells(myRow, strF0_col).EntireRow.Interior.ColorIndex = 28
End If
Next myRow
End Sub
Thanks in advance
Is there any reason to do not use Conditional Formatting, as #Doug Glancy suggested?
It worked quite fine here for me.
In case you want to give it a shoot, do as follows...
Choose the whole row
Open Conditional Formatting Menu (will depend on your Excel version. Anyway...)
Add the Rule =$KU2>$LE2+50
Set the format you want (maybe fill in yellow?)
Confirm
Copy format to other rows
Notice the row index (2, in this case) cannot have the $ symbol.
Hope it helps.
You probably don't want to highlight rows that are blank?
If so, use
If Cells(myRow, strF0_col).Value <> "" And _
Cells(myRow, strF0_col).Value = Cells(myRow, sF0_col).Value Then
As an aside, accessing cell values like this is quite slow. If you are only processing 100 rows then its fast enough, but if this number grows then you will find it slows down to a painful degree.
It is much faster to copy the range values to a variant array an then loop over that. Search SO for [Excel] "Variant Array" There are many answers that show how to do this and explain why it helps

Resources