Selecting data within a pivot table - vba

I have some VBA code which needs to select Prod. Code, Lims#, SampleID, Log Date, District Name, Region, Machine ID, Ash, cNDF, CP, Ca, Cl from a pivot table.
When I use Entire row, I can select all the data that I need to make a clean paste into column A. However, now I'd like to paste into column
.PivotItems(PivotFieldName.Caption).DataRange.EntireRow.Select
I've attempted to do just data range, however it won't pull Prod.Code, Lims#, etc columns. It will only grab the analyte columns.
.PivotItems(PivotFieldName.Caption).DataRange.Select
I also tried to do a range off of the EntireRow, however then I can't figure out how to get last column or last row for that selected Prod. Code.
.PivotItems(PivotFieldName.Caption).DataRange.EntireRow.Range("A1:BB1").Select
How can I got about getting all columns for a Prod. code selected like the Entire Row method excluding the extra rows?
The Prod.Code Columns & Rows can shift in size depending on the data so I need to make it capable of grabbing the right range.
Further code structure:
Dim PvtTbl As PivotTable
Dim PvtFld As PivotField
Set PvtTbl = Sheets("NEP Pivot").PivotTables("NEP_Pivot")
Set PvtFld = PvtTbl.PivotFields("Prod. Code")
For Each PivotFieldName In PvtFld.PivotItems
'PivotFieldName.Caption represents "EHB"
If IsError(Application.Match(PivotFieldName.Caption, rngList, 0)) Then
With PvtFld
On Error Resume Next
.PivotItems(PivotFieldName.Caption).ShowDetail = True 'Show pivot item
.PivotItems(PivotFieldName.Caption).DataRange.EntireRow.Copy
Destination:=Sheets(PivotFieldName.Caption).Range("A3")
...
..
.

Use the .DataBodyRange property instead to get all the data within the pivot
PivotTable.DataBodyRange Property (Excel)
Returns a Range object that represents the range of values in a
PivotTable. Read-only.
Syntax
expression . DataBodyRange
expression A variable that represents a PivotTable object.
As you also want the row element you can do the following you can resize the data body range according to the difference in column count between the larger TableRange2 property and that inside pivot area. Be aware that grand totals etc may affect this but this shows you how to start thinking about it. There is also a TableRange1 property available with pivots.
Example pivot:
Code:
Option Explicit
Sub test()
Dim ws As Worksheet
Dim pvt As PivotTable
Dim columnsDifference As Long
Set ws = ActiveSheet
Set pvt = ws.PivotTables("PivotTable4")
columnsDifference = pvt.TableRange2.Columns.Count - pvt.DataBodyRange.Columns.Count
With pvt.DataBodyRange
Debug.Print .Offset(, -columnsDifference).Resize(.Rows.Count, .Columns.Count + columnsDifference).Address
End With
End Sub
I would recommend reading up on referencing pivottable ranges in VBA.
There are a variety of properties that you can use to determine ranges e.g. LabelRange and DataRange for fieldItems. You seems to have explored some of these. My experience has been that these are influenced by your pivottable layout and you will need to determine the current combination of methods to get your data.
For example, I used the following to get all the data for EHB with data laid out as follows:
Option Explicit
Sub test()
Dim ws As Worksheet
Dim pvt As PivotTable
Dim columnsDifference As Long
Dim wb As Workbook
Set wb = ThisWorkbook
Set ws = wb.Worksheets("mySheetName")
Set pvt = ws.PivotTables("NEP_Pivot")
columnsDifference = pvt.TableRange2.Columns.Count - pvt.DataBodyRange.Columns.Count
With pvt.DataBodyRange
Debug.Print pvt.PivotFields("Prod. Code").PivotItems("EHB").LabelRange.Offset(-1, 0).Resize(pvt.PivotFields("Prod. Code").PivotItems("EHB").LabelRange.Rows.Count, .Columns.Count + columnsDifference).Address
End With
End Sub
This produced the result
$C$11:$N$13
Notice how I have had to combine functions to get this result and if the pivottable layout gets changed this falls apart.
I was also able to write using:
With pvt.TableRange1
Debug.Print pvt.PivotFields("Prod. Code").PivotItems("EHB").LabelRange.Resize(pvt.PivotFields("Prod. Code").PivotItems("EHB").LabelRange.Rows.Count, .Columns.Count).Offset(-1, 0).Address
End With

Related

VBA Copy Pivot Table

Hi i want to copy my pivot table to another sheet. However there is an error with object doesn't support this property or method
Sub Project1()
Dim Table1 As PivotTable
Set Table1 = Worksheets("Bklg Pivot").PivotTables("PivotTable2")
Table1.Copy Destination:=ThisWorkbook.Sheets("Table2").Range("A1")
End Sub
The PivotTable object does not have a Copy method which is why your attempt is failing. Available methods are listed in the documentation.
You can use the TableRange2 property of the source PivotTable to copy as this returns a Range object which does have a Copy method. Below is an example where I am copying a PivotTable to another range within the same sheet.
TableRange2: Returns a Range object that represents the range
containing the entire PivotTable report, including page fields.
Read-only.
Sub CopyPivot()
Dim pvt As PivotTable
With ThisWorkbook.Worksheets("Sheet1")
Set pvt = .PivotTables("PivotTable1")
pvt.TableRange2.Copy .Range("E1") 'copy to another area within same sheet
End With
End Sub

Remove rows from selectrange VBA

Im trying to write a VBA to copy and paste alot of different data, there is a lot of non-important data in each sheet so i want to copy only the important part.
The VBA i have now looks like this:
Sub DynamicRange()
'Best used when your data does not have any entirely blank rows or columns
Dim sht As Worksheet
Dim StartCell As Range
Set sht = Worksheets("Kvalitetskriterier 2015")
Set StartCell = Range("A8")
'Select Range
StartCell.CurrentRegion.Select
End Sub
What I need is a way to, from the seleced range, remove the first row and the last 4 rows as i dont need that part. Is there a way to do that from my VBA?
There's no need to Select the range if you want to copy it, you can directly Copy it.
if you want to get rid of the first row of the Range, you can use Range.Ofset(1, 0), this will remove the first row (Header).
If you also want to get rid of rows at the end of your Range, you can use Range.Resize(- number of rows you want to remove).
Code
Sub DynamicRange()
'Best used when your data does not have any entirely blank rows or columns
Dim sht As Worksheet
Dim StartCell As Range
Set sht = Worksheets("Kvalitetskriterier 2015")
Set StartCell = sht.Range("A8")
'Select current region
Set StartCell = StartCell.CurrentRegion
' set offeset 1 row (remove header), and use Resize to remove the last row
Set StartCell = StartCell.Offset(1, 0).Resize(StartCell.rows.Count - 2)
StartCell.Copy ' <-- No need to Select it if you want to copy
End Sub

Run time error -2147024809 (80070057) - Pivot Table field name is not valid

Got another Excel VBA Macro button issue.
I am trying to make a button to refresh all pivots on a worksheet (there are four). I have been to StackOverflow before and received a solution that worked well. I took the code I was provided before and updated it for the new workbook but it fails below with the function .ChangePivotCache PvtCache:
Sub Button1_Click()
Dim PvtTbl As PivotTable
Dim PvtCache As PivotCache
Dim PvtDataRng As Range
Set PvtDataRng = Worksheets("OTR_Promo_List_ADV_2017").Range("B2:AU500")
Set PvtCache = ActiveWorkbook.PivotCaches.Add(xlDatabase, PvtDataRng)
Set PvtTbl = Worksheets("Desired_Distribution").PivotTables("PivotTable1")
For Each PvtTbl In Worksheets("Desired_Distribution").PivotTables
Set PvtCache = ActiveWorkbook.PivotCaches.Add(xlDatabase, PvtDataRng)
With PvtTbl
.ChangePivotCache PvtCache
.RefreshTable
End With
Set PvtCache = Nothing
Next PvtTbl
End Sub
The only differences are that the workbook changed and now I want to refresh 4 pivots instead of 2 - could that be the issue?
Below a screenshot so you can see the worksheets. "OTR_Promo_List_ADV-2017" is the database. The Pivot tables have the default naming, I did not change the names (i.e. PivotTable1, PivotTable2...)
Thanks!
The code you use to refresh all pivot tables on the one sheet seems overly complex. I don't quite understand why you would want to use .ChangePivotCache at all. It changes the data source of the specified pivot table. If you just want to refresh a pivot table, that is completely unwarranted.
You can use Excel Table objects as the data source for your pivot tables, then a simple refresh will suffice. Or, if you don't want to use Tables (though you may really want to look into that, for obvious reasons), you can use dynamic range names to define the pivot source. With both techniques, you only need to refresh the pivot table and don't have to manipulate the pivot cache with VBA.
With Tables or dynamic range names as the source of pivot tables, you can refresh all pivot tables on a sheet by cycling through them and refresh them with codes along these lines:
Sub RefreshPivotsOnSheet()
Dim ws As Worksheet
Dim pt As PivotTable
Set ws = Worksheets("MySheet")
For Each pt In ws.PivotTables
pt.RefreshTable
Next pt
End Sub
Edit: How to set Excel Tables as the data source for a pivot: Turn the source data into a table with Ctrl + T or Insert > Table. Then edit the Pivot Table data source and point it to the Excel table you just created.
I was able to close this topic. I found somewhere else a simple macro that says only:
Sub REFRESH()
'
' REFRESH Macro
'
'
ActiveWorkbook.RefreshAll
End Sub
seemed to do the trick.
Thank you for all your inputs!

Referencing Autofilter Results in VBA

I am currently experimenting using VBA and autofilter to query a dataset (as per Populate Excel Data Validation Drop-Down From Data Range Condition Using VBA )
However I am having trouble using VBA to refer to the auto filter results.
How can I collect results without needing to copy and paste? (for example to store a result as a variable)
How can I check how many results have been found, and trigger a msg box when the auto filter produces no results?
Thanks for your help
You may use the special parameters xlCellTypeVisible and SpecialCells.
Sub Test()
Dim SheetERP As Worksheet
Set SheetERP = Worksheets("MyDatas") 'Sheet with data
Dim myTabela As Excel.ListObject
Set myTabela = SheetERP.ListObjects("CodeData") 'Named Table range
Dim qtd As Integer 'To count filtered data rows (only visible)
qtd = SheetERP.ListObjects("CodeData").DataBodyRange.Columns(1).SpecialCells(xlCellTypeVisible).Count
'OR
qtd = myTabela.DataBodyRange.Columns(1).SpecialCells(xlCellTypeVisible).Count
MsgBox qtd
Dim TFiltro As Range
Set TFiltro = SheetERP.UsedRange.SpecialCells(xlCellTypeVisible)
'OR
Set TFiltro = myTabela.DataBodyRange.SpecialCells(xlCellTypeVisible)
'Do what you want with TFiltro
End Sub

Creating a parameterized query in Excel with SQL using a cell as a parameter

So in MS Excel I've imported a table from a database in a SQL Server. I want to create a parameterized query where you have two cells. Say these two cells are G1 and G2. G1 takes a parameter/category and G2 takes a value from the parameter/category and queries the table you imported (essentially a WHERE clause that is dynamic from cell input). Can someone show me how to do this?
EDIT: Based on a chat session, we discovered that the first parameter is the column to be searched and the second parameter is the value to filter.
You can do what you want by filtering the table you imported.
Use the code below as your template. Modify it to reference the correct worksheets and ranges.
Sub FilterByParameter()
Dim wb As Workbook
Dim dataSheet As Worksheet
Dim parameterSheet As Worksheet
Dim rng As Range
Dim filterColumn As Long
Dim filterValue As String
Set wb = ThisWorkbook
' sheet that contains your table
Set dataSheet = wb.Sheets("Sheet1")
' sheet that contains your parameters
Set parameterSheet = wb.Sheets("Sheet2")
' range that contains your table, hard-coded here
' but can easily be set dynamically
Set rng = dataSheet.Range("A1:F78")
' get the column you are searching
filterColumn = parameterSheet.Range("G1").Value
' get the value you want to filter on
filterValue = parameterSheet.Range("G2").Value
' turn off autofilters if set
dataSheet.AutoFilterMode = False
' autofilter using your column and filter
rng.AutoFilter field:=filterColumn, Criteria1:=filterValue
' now you can do whatever you want to with the rows
' that remain after the autofilter was applied
End Sub
See Efficient way to delete entire row if... for an example of how to use the visible rows.