How to select data range dynamically for pivot table - vba

I have searched this topic exhaustively however I am struggling to find a solution which works for my macro. I need the source data for a pivot table to include all rows (containing data) on a sheet. The amount of rows will change daily.
Here is what I've got so far:
Sheets("Sheet1").Select
Sheets("Sheet1").Name = "RAW_DATA"
Range("A1").Select
Sheets.Add
ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:= _
"RAW_DATA!R1C1:R159C24", Version:=xlPivotTableVersion14).CreatePivotTable _
TableDestination:="Sheet4!R3C1", TableName:="PivotTable1", DefaultVersion _
:=xlPivotTableVersion14
Sheets("Sheet4").Select
Cells(3, 1).Select
With ActiveSheet.PivotTables("PivotTable1").PivotFields("Asset")
.Orientation = xlRowField
.Position = 1
End With
The values which represent my pivot tables source data are RAW_DATA!R1C1:R159C24. The problem is that I need this range to dynamically increase or decrease depending on the size of the populated source data range.

First of all, you might be able to easily solve your problem by just setting the columns as your datarange (E.g. RAW_DATA!$A:$X).
When the data is appended a simple update on the pivot will include new data or exclude the data that is no longer there.
That said, here's a VBA solution:
This Example will change the source data for PivotTable1 on Sheet1 to be "RAW_DATA!$A$1:$X$ whatever the last row is"
Sub ChangePivotData()
Dim lastrow as double
lastrow = Worksheets("RAW_DATA").Range("A" & Rows.Count).End(xlUp).Row
With Worksheets("Sheet1").PivotTables("PivotTable1")
.ChangePivotCache ActiveWorkbook.PivotCaches.Create( _
SourceType:=xlDatabase, _
SourceData:="RAW_DATA!A2:X" & CStr(lastrow), _
Version:=xlPivotTableVersion14)
End With
End Sub
That is the core of it. However, you might want to check for blank column headers to do some error prevention, automatically refresh the table after the new cache has been set, etc.
More extensive example can be found here:
http://www.thespreadsheetguru.com/the-code-vault/2014/7/9/change-a-pivot-tables-data-source-range
Enjoy :)

You can use the below if your data is the only thing in the sheet
Worksheets("RAW_DATA").Usedrange
and the corresponding range address
Worksheets("RAW_DATA").Usedrange.Address
Hope this helps

Related

Excel VB Advanced Filter Copy with Condition

I am trying to put a condition on each row copied. I want all uniques but only if they also have a specific value in another field.
This is what I have to grab all uniques (and it works) but I can't figure out how to get only the rows with a specific value in column J.
r1.Columns(20).AdvancedFilter xlFilterCopy, , Sheet11.Range("A1"), unique:=True
I have tried doing a CriteriaRange but I can't seem to get the syntax correct for it. Additionally I thought about an If statement but logically in my head it means it would fire off the whole list every time it has a true statement, not on a per row basis.
Here is how I thought it might work. But I get a type mismatch error.
r1.Columns(20).AdvancedFilter xlFilterCopy, r1.Columns(10).Value = "November", Sheet11.Range("A1"), unique:=True
Thoughts?
First of all, your Criteria Range should be just that - a Range with the header corresponding to the column to be filtered, and criteria underneath. For example, D1:D2 in this snapshot:
Secondly, you won't be able to copy just a single column (20) while filtering another column (10) in the same step.
You can tweak the Advanced Filter to
First filter the entire list in place based on the criterion provided
And then copy the visible cells in the column in question
Something like this (change Sheet and Range references as needed):
Sub MyFilter()
Dim lastRow As Long
With Sheet1
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
.Range("A1:B" & lastRow).AdvancedFilter _
Action:=xlFilterInPlace, CriteriaRange:=.Range("D1:D2"), Unique:=True
With .Range("B1:B" & lastRow).SpecialCells(xlCellTypeVisible)
.Copy Sheet2.Range("A1")
End With
.ShowAllData
End With
End Sub
To be able to keep the other parts of the code that worked perfectly. I added a hidden sheet and wrote a macro to copy the filtered results out to the new hidden sheet. Then I ran my original code against the filtered data on that hidden sheet.
Sub FilterLiveToDataSheet()
' Unhide Required Sheets
Sheets("Original-Data").Visible = True
Sheets("Filtered-Data").Visible = True
' Delete Old Data
Sheets("Filtered-Data").Select
Cells.Select
Selection.ClearContents
' Copy Filtered Data
Sheets("Original-Data").Select
Range("TBL_ATTR_Spend[[#Headers],[HeaderName]]").Select
Selection.AutoFilter
ActiveSheet.ListObjects("TBL_ATTR_Spend").Range.AutoFilter Field:=10, _
Criteria1:="Delta"
Cells.Select
Selection.Copy
' Paste to Data Sheet
Sheets("Filtered-Data").Select
Cells.Select
ActiveSheet.Paste
' Unfilter Original Data Page
Sheets("Original-Data").Select
Range("TBL_ATTR_Spend[[#Headers],[HeaderName]]").Select
Selection.AutoFilter
' Hide Required Sheets
Sheets("Original-Data").Visible = False
Sheets("Filtered-Data").Visible = False
' Go to Results Sheet
Sheets("Results").Select

sort and subtotal preselected data

I'm working with a worksheet and at some point within there is a list of costs. However this list changes so can have varying numbers of rows. My ultimate goal is to sort and then subtotal this list of costs. Because the number of rows I want to sort and subtotal are always different, I was thinking I could make a macro that would only work off of preselected data eg the user to select the cells range to apply to be sorted and subtotalled. I can't just work off of all active cells, as there are some rows I don't want to include in the sort and subtotal.
I've recorded the following simple macro to sort and subtotal data, however, you'll note it only works for the cells that were selected when I recorded the macro. Does anybody know how to modify the macro so that the user can firstly manually select the cells range with the mouse and then click a button that automatically sorts the preselected data and subtotals it? any help very appreciated, thank you.
Sub Sort_and_Subtotal_CheckBox()
ActiveWorkbook.Worksheets("dummy").AutoFilter.Sort.SortFields.Clear
ActiveWorkbook.Worksheets("dummy").AutoFilter.Sort.SortFields.Add Key:=Range( _
"B151:B159"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("dummy").AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Range("B151:K156").Select
Selection.Subtotal GroupBy:=1, Function:=xlSum, TotalList:=Array(10), _
Replace:=True, PageBreaks:=False, SummaryBelowData:=True
End Sub
Try this code. This will allow the user to select the range by using an Input box.
Dim SortRng As Range
Set SortRng = Application.InputBox("Select the range to sort", "Select Range", 0, , , , , 8)
SortRng.Select
Selection.Sort Key1:=SortRng, Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
Range("A1").Select
If you would like to obtain the selected range, you could simply request Selection.Address in VBA. However, I believe that this assumes that the selection is a block of cells, so this might not always give the desired result (e.g. in case of multiple selected ranges). Another solution might be to convert the list of costs to a table. In your macro you can then simply refer to a named range, namely, the column in the newly created table. The table will work as a dynamic named range and will always include the entire range of values in it. If you can be sure that there will be no data below the list of costs, a second option would be to check the last row that is not empty within the column where the list of costs is stored. Something in the likes of .Cells(.Rows.Count, "A").End(xlUp).Row to get the last row of the column that contains the list.

Trying to copy a formula down an entire column to the last row of data in an adjacent column

I am a new VBA user, and I am trying to create a VBA code to copy a single Vlookup formula down an entire column to the last row of data in an adjacent column. I don't want to specify a specific range, because I intend to use this macro with multiple different files that have different row ranges, so I am looking for a code that will simply copy down to the last value in an adjacent column.
I have tried looking at other similar questions and answers on this website, but none of the solutions that I have found have been working, and I would really appreciate some help!
Here is my code that I currently have:
' Section5 Macro
ActiveCell.FormulaR1C1 = _
"=VLOOKUP(RC[6],'[PERSONAL.XLSB]Task and Sections'!R2C1:R254C2,2,FALSE)"
Range("C2").Select
Selection.Copy 'Copy Vlookup Formula
Dim lastRow As Long
lastRow = Range("B" & Rows.Count).End(xlUp).Row
Range("C3").AutoFill destination:=Range("C3:C" & lastRow) 'Specify range for Column C based off of row count in Column B
Application.CutCopyMode = False
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False 'Paste Vlookup equation down the column
End Sub
The formula I want to copy is "=VLOOKUP(RC[6],'[PERSONAL.XLSB]Task and Sections'!R2C1:R254C2,2,FALSE". The column that I want to copy this formula down is column C (in all rows except C1 which is the Header). The column that I want to refer to for row length is the adjacent column B.
Currently I am getting an error that says "Compile error: Named argument not found".
Any help would be greatly appreciated!
Thank you,
As pointed in the comment, you had a simple typo ("desination")... Nevertheless, your code doesn't seem to work even when this is fixed.
There's a much simpler approach. Try this:
Sub FillWithFormula()
Dim lastRow As Long
lastRow = Range("B" & Rows.Count).End(xlUp).Row
Range("C2:C" & lastRow).FormulaLocal = "=B2*2"
End Sub
Notice that I replaced your formula with a simpler one (independent of external data) so I could verify that the routine works.
Here.
Sub thing()
Dim lastRow As Long
lastRow = Cells(Rows.Count, 2).End(xlUp).Row
Range("C3:C" & lastRow).FormulaR1C1 = "=VLOOKUP(RC[6],'[PERSONAL.XLSB]Task and Sections'!R2C1:R254C2,2,FALSE)"
Range("C3:C" & lastRow).Value = Range("C3:C" & lastRow).Value
End Sub
Simpler, more elegant. Hasn't this kind of thing been solved like a million times all around the internet? Anyway, copy-paste is the slowest thing you can do in a macro. Avoid it. Just set the values of a range to be the values of the range. :)
Also, you can assign a formula to a whole range.

VBA query: using clipboard data to filter

I'm using multiple worksheets in Excel to create a database of candidates undergoing some technical training. Each time a candidate is added to the 'database' they are assigned a unique number, for example "2015-0001". When they call to pay their deposit, I'm using a data input table for the telephone operator to note down the details, and it looks up the unique number for the candidate. I then want to filter the main database for the candidate by their number and paste in the confirmed details of the deposit.
My query is this: how do I write the code that copies the candidate number data from the cell on worksheet 1 and then uses that data (irrespective of its value) to filter worksheet 2?
I'm new to macros and have been using "record macro" to generate code which I then edit and learn as I go. So, apologies if this looks extremely clunky. Using record, the filter command simply takes the example text I'm using (in this case 2015-0011), not replacing it with the revised value when the Deposit input table is changed and the macro is run. Am I right to think that I need to use a String?
Thanks in advance. RLC
Sub Confirm_Deposit()
'
' Confirm_Deposit Macro
'
'
Sheets("Take Deposit").Select
Range("C5").Select
Selection.Copy
Sheets("CIP Candidates").Select
ActiveSheet.Range("$A$6:$AK$2507").AutoFilter Field:=1, Criteria1:= _
"2015-0011" <---------------- ISSUE
Sheets("Take Deposit").Select
Range("C6:C8").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("CIP Candidates").Select
Range("A6").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Offset(0, 20).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=True
Application.Run _
"'CIP Spreadsheet RLC (with Macros).xlsm'!ThisWorkbook.Clear_Filters"
etc.
This is a different approach that is less "Macro" based and more just simple cell manipulation using loops. It's very flexible. See what you think of the idea, then we can modify to your specific needs.
The part of this code that I would change immediately is selecting where the lookup value comes from. In this example, since I don't know your specifics, I saw you are using "C5" in the example above.
Sub Confirm_Deposit()
Dim source As String
Dim target As String
Dim lookupVal As String
Dim row As Long
Dim searchRow As Long
source = "Take Deposit" 'In case you have similar projects, you can just replace these lines.
target = "CIP Candidates"
lastSourceRow = Sheets(source).Range("A" & Rows.Count).End(xlUp).row
lastTargetRow = Sheets(target).Range("A" & Rows.Count).End(xlUp).row
lastTargetCol = Sheets(target).Cells(1, Columns.Count).End(xlToLeft).Column
lookupVal = TextBox1.Text 'Set the lookupVal from whatever source you choose. I like ComboBoxes when I can.
For searchRow = 2 To lastSourceRow
If Sheets(source).Cells(searchRow, 3).Text = lookupVal Then 'Searching through Source Sheet on Col "C"
Exit For
End If
Next searchRow
'This way, at the end of the search, you have the row number of the original source to be copied, instead of hard coding.
For row = 6 To lastTargetRow 'Loop through the Target Sheet
If Sheets(target).Cells(row, 3).Text = lookupVal Then 'Compare lookupVal to the Range being looped.
For col = 2 To lastTargetCol
Sheets(target).Cells(row, 3) = Sheets(source).Cells(searchRow, col) 'Copies contents from Row 5 of source sheet.
Next col
End If
Next row
End Sub
EDIT: Made lookup Row dynamic instead of hard coded to row 5
Been a while but will this do the trick?
ActiveSheet.Range("$A$6:$AK$2507").AutoFilter Field:=1, Criteria1:= _
Sheets("Take Deposit").Cells(5,3).Value
or
ActiveSheet.Range("$A$6:$AK$2507").AutoFilter Field:=1, Criteria1:= _
Sheets("Take Deposit").Range("C5").Value
theres no need to select and copy the value. You can just reference the Cells Value.

PivotTable Macro Field name error in Excel

I am getting following error for the Macro I have created to insert Pivot table.
It was working before without any problem, I didn't change anything.
Here is the Error
Here is my code
Cells.Select
Sheets.Add.Name = "Detail"
ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:= _
"Log!R1C1:R65536C11", Version:=xlPivotTableVersion10).CreatePivotTable _
TableDestination:="Detail!R3C1", TableName:="PivotTable1", DefaultVersion _
:=xlPivotTableVersion10
Sheets("Detail").Select
Cells(3, 1).Select
The error is indicating that you have an untitled column(s). Go back and make sure none of the columns in the SourceData range (i.e. columns 1 to 11) have a blank header.
That can occur with blank names in the header row, or if you're creating a PivotTable with the same name with PivotTable1 (thus why it worked the first time).
Were you deleting the PivotTable in the past?