I am automating some Excel file creation from Access. I need help with dynamically resetting the pivotcache for all the pivot tables. The first set of code is me testing working code in Excel. Now I want to translate this so that it runs from Access module.
Sub Update_PTSource()
With Sheets("Pivot")
.PivotTables(1).ChangePivotCache ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=Sheets("Data").Range("data"))
End With
End Sub
Function pivot_refresh_test()
Dim pt As Variant
Dim wb, ws As Object
Dim strWBName As String
Dim strTabName As String
strWBName = "C:\Users\...\Packaged SKU.xlsb"
strTabName = "Pivot"
Set wb = GetObject(strWBName)
For Each pt In wb.Sheets(strTabName).Pivottables
pt.ChangePivotCache wb.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=wb.Sheets("Data").Range("data"))
pt.RefreshTable
Next pt
End Function
I'm getting error on pt.ChangePivotCache line with error
invalid procedure call or argument
As far as I can see, you've only made one simple error:
xlDatabase is an Excel enum, and since you're using late bindings, you don't have access to it. You can use it's integer value, 1, instead:
For Each pt In wb.Sheets(strTabName).Pivottables
pt.ChangePivotCache wb.PivotCaches.Create(SourceType:=1, SourceData:=wb.Sheets("Data").Range("data"))
pt.RefreshTable
Next pt
I'm anal about using the least code possible when designing solutions so I found a much easier method to what I wanted to do.
My task was to update and refresh the source data of all my pivot tables. There was one source, multiple pivot tables. I created a dynamic named range for my source for this purpose in my template Excel book that Access was writing into. I never save over the template I just used saveas vba to create the filled copy.
However, since I had created a named range and am modifying always the same template file with Access, I don't need to write a program to change my pivotcache. I can just use 'Change Data Source' in Excel ribbon. The vba code gets much easier. It is just a variation of: ThisWorkbook.RefreshAll. No code loops required!
The whole power of my strategy is the formula that creates my named range. =Data!$A$5:OFFSET(Data!$A$5,COUNTA(Data!$A:$A)-1,52). You just set the first cell of your data, and set how many columns there are for your fields, the rows are automatically adjusted.
I hope this little rant help whoever navigates here. I've been searching a lot for good dynamic pivot table automation but most of the internet has crap info on this.
Related
I use a lot of Vlookup to find prices in a certain file (c:/pricelist.xlsx), using the product code. I would like to simplify it by creating a new VBA function, but it does not work.
Function findprice(codes)
Dim price
Dim pricebook As Workbook
Dim pricesheet As Worksheet
Dim pricerange As Range
Dim coderange As Range
Set pricebook = Workbooks("c:\info\pricelist.xlsx")
Set pricesheet = pricebook.Sheets("Sheet2")
Set pricerange = pricesheet.Range("FF1:FF20000")
Set coderange = pricesheet.Range("H1:H20000")
findprice = Application.Index(pricerange, Application.Match(codes, coderange, 0))
End Function
I can't say for sure since your question didn't include any sample data or explanation of what/why you're trying to do, but I suspect you're over-complicating this is a few ways.
You don't need a custom function to call a worksheet function from the worksheet. Just use the worksheet functions instead.
In this case VLookup is easier and saves a step (as you suggested in your title.)
Instead of referring to huge ranges of two cells, just refer to the whole columns.
Referring to cells in another Excel file is just like any other formula that refers to another file. (More infor here)
You should be able to use something like this on the worksheet:
=VLOOKUP(A1,'c:\info\pricelist.xlsx'!$H:$FF,155,FALSE)
...where A1 is the value to match (ie., codes).
If you do need this is VBA for some reason, it's easy to adapt just like your sample function.
More Information:
Office Support : Create or change a cell reference
Office Support : Create an external reference (link) to a cell range in another workbook
I'm trying to dynamically resize a ListObject table after pasting data in the rows below with VBA. Resizing works fine as long as Sheet02, where it happens, is the active sheet - but throws an error when Sheet02 is not the active sheet. What am I missing?
Code snippet:
Function Resize()
lastRow = Sheet02.Cells(Rows.Count, "G").End(xlUp).Row
newRange = "$A1:$G$" & lastRow
Sheet02.ListObjects("tblDb").Resize Range(newRange)
End Function
The Error: Run-time error '1004': Application-defined or object-defined error
After running some more tests with data below the table put there by hand revealed no issues with any errors whatsoever - not within the sheet, nor from outside of it.
The problem in my case was as follows:
I was importing data from a .CSV file by using QueryTables.Add, utilizing the import utility Excel comes with. Turns out in doing so, it creates a Query Connection, a live "Link" to the file you imported, so it can automatically update itself with new data from that file should it change.
Using the import within the existing Table object in Excel didn't work, because Table objects and Query Connection content don't get along particularly well, as it turns out. At this point you might realize where this is going.
So I expanded the code to import from the .CSV just below the table, then proceeded to remove the Query Connection from the sheet, and resize the table over the now disconnected, plain text contents of the imported .CSV file.
The ImportCSV function just so happened to include this particular snippet of code:
For Each queryConnec In ActiveSheet.QueryTables
queryConnec.Delete
Next queryConnec
And that's the reason why it worked within the Sheet - because I imported from within the sheet and the Query Connections have been removed in doing so. When importing from outside the sheet, the Query Connections were of course not removed, which is why resizing the Table over the live Query Connection content threw an error...
Fixed easily by:
For Each queryConnec In Sheet02.QueryTables
queryConnec.Delete
Next queryConnec
tl;dr: A tiny oversight for a programmer, turned into a huge issue for Excel.
Try not updating the screen and changing the focus to sheet02. Next, make your change to sheet02. Finally, return the focus to whatever sheet you were on.
Function Resize()
Let Application.ScreenUpdating = False
Dim Current_Worksheet As Worksheet
Dim Sheet_02 As Worksheet
Set Current_Worksheet = ActiveSheet
Set Sheet_02 = Sheet02
Let lastRow = Sheet_02.Cells(Rows.Count, "G").End(xlUp).Row
Let newRange = "$A1:$G$" & lastRow
Call Sheet_02.Activate
DoEvents
Sheet_02.ListObjects("tblDb").Resize Range(newRange)
DoEvents
Call Current_Worksheet.Activate
Let Application.ScreenUpdating = True
End Function
The title is pretty self-explanatory.
I have a named table, Table_Unit_2_Data, which I would like to set as the source data for a chart that will be created using VBA.
During the recording of a macro I selected the entirety of the table, and inserted a chart. This is the code that I got (Build is the name of the Sheet):
Sub Test()
Range("Table_Unit_2_Data[#All]").Select
ActiveSheet.Shapes.AddChart2(240, xlXYScatterSmoothNoMarkers).Select
ActiveChart.SetSourceData Source:= Range("Build!$Y$1:$AD$2")
End Sub
Well, for one thing, as you can see, a specific $A$1 range is passed into the SetSoureData. This will not work because the range of Table_Unit_2_Data will change.
I attempted this:
With Sheet2.Shapes.AddChart2(240, xlXYScatterSmoothNoMarkers)
.Chart.SetSourceData (Sheet2.Range("Table_Unit_2_Data[#All]"))
End With
But then I get the error "Object Required".
I can't seem to phrase my search queries in such a way as to find relevant answers to this specific question on the internet so I apologize for asking what is likely a redundant question. If someone could help me with this problem I would be greatly appreciative and if anyone has a good article or source online for information regarding the nuances of chart creation within VBA that would also be very helpful.
Thank you.
In addition to what Domenic said (which is correct + would cause the "Object Required" error), your code doesn't make it clear what "Sheet2" is, except that it's the codename of some sheet. From the recorded macro, I can infer that the actual table is on a sheet called "Build", so another possibility to consider is that Sheet2 isn't actually the codename of Sheets("Build"). Again, I can't actually tell from the code provided.
While I do like using sheet codenames, I'd strongly recommend against using them if you're not going to make the names descriptive.
FWIW, there's another way to reference table ranges that's a little more flexible, especially if you're going to be referring to the table elsewhere in the code. Just make a ListObject variable:
Dim UnitTable2 As ListObject
Set UnitTable2 = Sheets("Build").ListObjects("Table_Unit_2_Data")
And you'll be able to reference any part of the table really easily:
Dim rng As Range
'Reference the whole table, including headers:
Set rng = UnitTable2.Range
'Reference just the table data (no headers):
Set rng = UnitTable2.DataBodyRange
'Reference just the data in a single column:
Set rng = UnitTable2.ListColumns("Col1").DataBodyRange
'Reference the headers only
Set rng = UnitTable2.HeaderRowRange
Very novice user here, just getting my feet wet. Please excuse this if it's an idiotic question - I'm quite sure what I'm doing yet.
I'm creating a userform with VBA and Excel. I've been successful in learning how to pull information from a pivot table so far, but I've run into a hitch.
When run my userform from another sheet it can't find the pivot table. Here's the code I'm using.
Set PT = ActiveSheet.PivotTables(1)
Works perfectly when I'm one that sheet, but I envision a scenario where I have multiple pivots on different sheets and will want to call info and cross-reference the data.
I thought maybe Set PT = ActiveWorkbook.PivotTables(1) would work, but of course it doesn't. Obviously I don't yet quite understand how to use a pivot table variable.
Does anyone know how I might go about doing this? Thanks so much.
If you open UserForm, workbook with UserForm open will be the active one. If I understand correctly, you want to refer to 1st object of PivotTables collection on a different sheet. To do so, define path of the file with pivot table, example below:
Dim path as string
Dim wbk as workbook
Dim PT As PivotTable
path= "C:\folder1\folder2\yourfile.extension"
set wbk = workbooks.open(path)
Set PT = wbk.worksheets("Sheet1").PivotTables(1)
'do your actions, save the file if you want to keep changes
wbk.close
set wbk = nothing
Alternatively work on all Pivot Tables in your worksheet, instead of:
Set PT = wbk.worksheets("Sheet1").PivotTables(1)
You can use a loop through collection, this example refreshes tables:
For Each PT In wbk.worksheets("Sheet1").PivotTables
PT.RefreshTable
Next PT
I am building a set of reports to be updated daily for some users who are not super savvy when it comes to pivot charts and pivot tables in Excel (2010). I have data from an already automated data pull from our db, but to make that information useful (and more simple to use), I want to generate the pivots using VBA.
I have already generated the pivot tables just fine and can manually manipulate them to create the relevant charts. As I create the tables (all on one sheet), I am labeling them (if that helps solve my problem). Where I am running into trouble is creating the pivot charts, and specifically, setting the data source.
Since the charts are based on pivots that may change in size depending on the data present, I can't just assign a fixed range as the source. Same problem with a named range, as I still don't know what range to assign a name, unless I can assign a PT as a range.
I've tried something like this, but that didn't work, since I'm not looking at an actual 'Range' object:
Dim MyChartObject As ChartObject
Dim MyChart As Chart
'These variables are assigned elsewhere in the code.
Set MyChartObject = wksMainCharts.ChartObjects.Add( _
iChartLeft, iChartTop, iChartWidth, iChartHeight)
Set MyChart = MyChartObject.Chart
MyChart.SetSourceData wksMainPivot.PivotTables(PivotName).SourceData 'Fails; requires Range object
'More code to follow...
I do know that this is a string representation of the wrong range, but I was playing with what I could figure on my own.
Essentially what I want is the opposite of this question, which seeks to find the pivot table at a specified range. I also reviewed this question, but it's not quite what I'm looking for (there are also no answers provided).
Also: I'm asking here for a way to get the range of a PT, which I think would be interesting to know, but ultimately, I just want to create the pivot chart, so if anyone wants to offer a better method than what I've started on, I'm completely open to that as well.
Is this what you are trying to achieve?
Sub Sample()
Dim Chrt As Chart, pvtTbl As PivotTable
Set pvtTbl = ActiveSheet.PivotTables(1)
Set Chrt = ActiveSheet.ChartObjects(1).Chart
Chrt.SetSourceData Source:=pvtTbl.TableRange1
End Sub
So your this line
MyChart.SetSourceData wksMainPivot.PivotTables(PivotName).SourceData
becomes
MyChart.SetSourceData wksMainPivot.PivotTables(PivotName).TableRange1