VBA Transpose From Specific Number of Cells Above - excel

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.

Related

How does one write a VBA macro which generates a SUMIFS table using a user selected column as an input in the formula?

Not sure if this is even possible but I'm just curious. I know you can make VBA automatically populate a formula in certain cells in Excel, and also that you can insert columns and such next to a user selected cell. Is it possible however to write a code in which the user selects a column that contains data 1 (dates for example), and then selects a column with data 2 (names for example) and a final column with data 3 (dollar values). Then the code would run on a predefined range (a table that has names as row headers and dates as column headers) and populate a SUMIFS formula into all the cells- with the user selected columns as the criteria range and the defined name rows and date columns as the criteria.
If someone can point me on the right direction I'd greatly appreciate this. I'm struggling to figure out how to structure this macro so that a user input variable can be used inside the SUMIFS formula, changing the criteria range in the formula based on what the user selects. Let me know if this even seems possible in VBA.
I've tried creating macros which automatically populate a formula like SUMIF into a range, but the problem is that the formula has to be fixed in the VBA code with certain constants. What I'm looking for would have to be variable, and the parameters of the formula be taken from user inputs.
Appreciate any help or knowledge on this topic. Thanks.
In code I used before I needed to be able to select a column and then use it later on,
On Error Resume Next
Set columnStart = Application.InputBox("Select the column of the first key", Default:=Selection.Address(0, 0), Type:=8)
On Error GoTo 0
If columnStart Is Nothing Then
MsgBox "Cancelled."
GoTo EndSkip
End If
Set wbV = columnStart.Parent.Parent
columnAddress = columnStart.Address
columnNr = columnStart.Column
wbV.Activate
Set ws = wbV.ActiveSheet
and use it later on in a VLOOKUP
Range("N2:N" & Lastrow).FormulaR1C1 = _
"=IFERROR(VLOOKUP(RC[-1],'[" & wbV.Name & "]" & ws.Name & "'!C" & columnNr & ",1,0), ""0000NO"")"
This should help you how to use them as variables in a formula.
I believe my info came partly from here User input box to pick column to perform action

Generating a filter loop based off of two criteria in another sheet?

At my job I have automated a very manual task and to the point they have wanted to expand it to the other department where they work a little differently. So the goal of this is I want to be able to filter column "A" and then filter another column based off of phrases that I already have in place as well. The data in column "A" I would have a source in another sheet, but it would have around potentially 200-400 possibilities to look for. After it filters column A I then want it go to column "AG" and then do another loop filtering based off of provided key phrases that the analyst would select based on a data validation. Once it filters those two criteria I then have the codes in place to generate the spreadsheets for the analyst. The code below is an example of the first block, I have 4 other codes that are pretty much the same they just generate different templates, I had to do multiple codes cause I didn't know how to do a loop based off of a source.
Sub Generate_Consolidated_Update_Reports()
Dim EDI As String
EDI = Environ("USERPROFILE") & "\desktop\foldername\foldername2\foldername3\filename " &
Format(Now(), "MM.DD.YY")
Workbooks("Master(where the filtering happens)").Activate
'The next line of code I am just doing the second filtering which is based off of a data validation
'I created, essentially the analyst would just select a key phrase and then that would
'prompt the code to generate the template, I haven't figured out how to do it based off of
'the source that's why I just have the specific name in the key range
'The first step to the code would need to be looking for anything in column "A", but like
'I said that could be anywhere from 200-400 possibilities. I have access to it, though and have
'it listed in "Sheet2" along with the phrases in column "AG" as well.
ActiveWorkbook.Worksheets("Master").Sort.SortFields.Add Key:=Range("AG:AG" _
), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With Selection
.autofilter Field:=33, Criteria1:="Send to EDI Team - Account Level"
.Offset(1, 0).Select
End With
'The next line of code will be seeing if it is empty, I realized that it would work once,
'but if there ever was data the next line of looking for empty would always
'just filter anyways and keep creating the template even though there was no data
'so I did this route where if it saw it was empty I called another code, would be awesome
'if I could figure that out too!
'This then goes on repeat down the line, it's 5 different codes, so it isn't clean. :/
'so I only did one so you wouldn't see a ton of fluff!
Dim Lr As Long
Lr = Range("A" & Rows.Count).End(xlUp).Row
If Lr > 1 Then
Workbooks.Add
ActiveWorkbook.SaveAs EDI & ".XLS"
Sheets("Sheet1").Select
Sheets("Sheet1").Name = "EDI Account Update"
'Redacted code, just fluff on creating the template for the analyst
'Next line is just doing the code to show all the data again
'Then within that if statement to then call another sub that is essentially the same process
'If the code doesn't find it it goes to else where it then just calls the other sub
If ActiveSheet.AutoFilterMode Then ActiveSheet.ShowAllData
Range("A1").Select
Call Create_EDI_Update_GroupLevel
Else
ActiveSheet.ShowAllData
Range("A1").Select
Call Create_EDI_Update_GroupLevel
End If
End Sub
The reason I have to also call other subs is because each criteria they select will generate a completely different template based on company policies and such.
Really sorry if this isn't clear, I am still learning coding and just having a hard time trying to explain exactly what I needed. Thank you so much for your time.
I wanted to add a comment but not enough reputation yet.
One question I have is: Are you filtering on one phrase among 200-400 or can it be multiple?
I can't be sure, however an Advanced Filter might help you in this case. It is not possible for me to go into all the details. There is a very good tutorial on Youtube about this (where I learned myself): VBA Advanced Filter - The FASTEST way to Copy and Filter Data
You can also use "Worksheet_Change" event to fill in the filter. Couple it with:
If Not Application.Intersect(Target,rngRange) is Nothing Then
' Your code here
' Where rngRange is a Range object that you want the change event to catch
End If
Another note is, you can use (considering data starts at "A1") Range("A1").CurrentRegion if you don't have any completely empty rows within your data instead of .End(xlUp). Actually you can use CurrentRegion in any cell that is inside the data range. Check out the behaviour by pressing CTRL + * after selecting a cell.
Dim rngData as Range
Set rngData = ws.Range("A1").CurrentRegion
' ws can be a worksheet object you can set alike range above or worksheet codename
' or Worksheet("SheetName")
' Then rngData.Row will give the top row of rngData
' rngData.Column will give you you the leftmost column
' rngData.Rows.Count will give the number of rows
' rngData.Columns.Count will give the number of columns
' rngData.resize() and rngData.Offset() helps a lot too, can be used in same line
' i.e., rngData.offset(2,0).resize(1,1) : move the range 2 rows down, resize to 1 row,1 column
' Do whatever with rngData
' After you are done clean up, doesn't matter most of the time in VBA but this is better
' from what I have read/learned from others
Set rngData = Nothing
This may not be the exact answer you are looking for, but may get you started. The video is 20 minutes long, see if it can be used in your case.
Edit 1: To further clarify
rngData part is more a general approach. You haven't said anything about being able to use Advanced Filtering but here how I would do it.
Assume, we have 3 sheets. wsData, wsFilter, wsReport.
wsData would be the sheet where data is entered.
wsFilter would only hold the filter criteria.
wsReport would be the sheet that you will export.
wsData, as an example assume row 1 is the header row.
wsFilter would be only 2 columns (with headers corresponding to A and AG), corresponding to Column A and AG.
On wsReport, you only have to clear contents and enter the column headers from wsData that you would want to appear on the customized report.
You will need 3 ranges, 1 for each worksheet. i.e., rngData, rngFilter, rngReport
The code to creating the report is easy as:
rngData.AdvancedFilter xlFilterCopy, rngFilter, rngReport
(I won't get into how to decide on the ranges as the video does it better than I would be able to).
Then next step should be: How to enter the filter criteria?

Sumif loop through data groups vba

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.

Use cell value/contents to determine an external reference file or sheet name?

I'm working on a cell formula that returns (via VLOOKUP?) a cell in a closed workbook (thus I believe INDIRECT will not work). The issue is that I want to use a value in the active sheet to determine the name of the sheet in the reference workbook and can't figure it out. Here's the best I've got.
=VLOOKUP($A3,'[Other Workbook.xlsm]ObsDFW'!$1:$800,COLUMNS($D4:D4)+3)
ObsDAL is the name of one of the sheets in the "Other Workbook". What I can't figure out is how to keep the "Obs" part of that name constant, but take the "DFW" from a cell value.
Using bad code, I want it to be:
=...[Master Statistics.xlsm]("Obs" & A1)'!$1:$800...
If context is helpful, the "Other Workbook" is full of hourly weather observations, separated into one sheet for each of a series of airports. I'm trying to pull this info into another file/workbook so I don't have to specify each airport specifically in the code many times over.
Thanks in advance!
You could try this VBA approach. This way you are adjusting Vlookup formula based on your dynamic_part (sheetname)
Sub VlookupClosedWorkbook()
Dim dynamic_part As Variant
dynamic_part = Range("B1").Value 'You should enter in cell B1 dynamic part of sheet name
For x = 3 To Range("A" & Rows.Count).End(xlUp).Row
Range("B" & x).Value = "=VLOOKUP(A" & x & ",'[Other Workbook.xlsm]Obs" & dynamic_part & "'!$1:$800,COLUMNS($D4:D4)+3,FALSE)"
Next x
End Sub
Assign this macro to shape and fire it after you change your dynamic part. When you trigger it for the first time, make sure that you have both Workbooks open.

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

Resources