I got a comment on my blog the other day from David, asking if we could make Power Query prompt for a folder at refresh, allowing us to choose which folder to should be used to consolidate files. That sounds like a pretty cool idea, and my first thought was “I think we can totally do that!”
I headed over to Chris Webb’s blog, as he’s done some cool things with Power Query prompts. Ultimately though, I got stuck on one thing… we have to go into the Query to invoke it. My (albeit limited) tests left me unable to have that prompt when we refresh the query.
Not to be outdone by a lacking feature though, I cooked up a solution using some Power Query and VBA techniques that I’ve shared before. This post wraps them up into a neat little package.
Background
The idea I’m going for here is to be able to click a button which:
- Prompts the user to select a folder,
- Feeds that folder into Power Query, and
- Refreshes the Power Query output table.
To set it up, I used 3 techniques that I’ve shared before:
- Building a Parameter Table for Power Query
- Implementing a Browse For Folder solution in VBA
- The concept from Refresh Power Query with VBA but this time for a single table only
Initial Setup
To begin with, I created a blank workbook, and immediately added a Power Query parameter table as outline in Building a Parameter Table for Power Query. I followed the steps there exactly, so I’m not going to detail that here. The only things of note were:
- I named the worksheet “Parameters”, and
- I used the following for my “File Path” value: D:\Consolidate\Begin
Next, I created a query to consolidate all the files in a folder. Basically I ran through the following steps:
- Power Query –> From File –> From Folder
- Chose my folder: D:\Consolidate\Begin
- Did a bit of cleanup on the file
- Implemented the “fnGetParameter” function call in place of the folder (as described in the aforementioned blog post)
The end result was some M code that looked like this:
let
Source = Folder.Files(fnGetParameter("File Path")),
#"Combined Binaries" = Binary.Combine(Source[Content]),
#"Imported CSV" = Csv.Document(#"Combined Binaries",null,",",null,1252),
#"First Row as Header" = Table.PromoteHeaders(#"Imported CSV"),
#"Changed Type" = Table.TransformColumnTypes(#"First Row as Header",{{"TranDate", type date}, {"Account", Int64.Type}, {"Dept", Int64.Type}, {"Sum of Amount", type number}}),
#"Renamed Columns" = Table.RenameColumns(#"Changed Type",{{"Sum of Amount", "Amount"}}),
#"Changed Type1" = Table.TransformColumnTypes(#"Renamed Columns",{{"Amount", type number}}),
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Changed Type1", {"TranDate"})
in
#"Removed Errors"
And returned results like this:
I then loaded the Power Query to the worksheet, and called the worksheet “Data”.
So far so good? Nothing really unusual yet.
Laying the Folder Change groundwork
With the basic functionality in place, I wanted to now give the user the ability to change the folder.
Rather than write the Browse For Folder routine from scratch, I headed over the VBAExpress.com and grabbed the one I submitted to the KB… um… a long time ago.
Once I had that code copied I:
- Opened the VBE
- Browsed into my workbook
- Right clicked the project and added a new Module
- Pasted in all the code (shown below):
Function BrowseForFolder(Optional OpenAt As Variant) As Variant
'Function purpose: To Browser for a user selected folder.
'If the "OpenAt" path is provided, open the browser at that directory
'NOTE: If invalid, it will open at the Desktop level
Dim ShellApp As Object
'Create a file browser window at the default folder
Set ShellApp = CreateObject("Shell.Application"). _
BrowseForFolder(0, "Please choose a folder", 0, OpenAt)
'Set the folder to that selected. (On error in case cancelled)
On Error Resume Next
BrowseForFolder = ShellApp.self.Path
On Error GoTo 0
'Destroy the Shell Application
Set ShellApp = Nothing
'Check for invalid or non-entries and send to the Invalid error
'handler if found
'Valid selections can begin L: (where L is a letter) or
'\\ (as in \\servername\sharename. All others are invalid
Select Case Mid(BrowseForFolder, 2, 1)
Case Is = ":"
If Left(BrowseForFolder, 1) = ":" Then GoTo Invalid
Case Is = "\"
If Not Left(BrowseForFolder, 1) = "\" Then GoTo Invalid
Case Else
GoTo Invalid
End Select
Exit Function
Invalid:
'If it was determined that the selection was invalid, set to False
BrowseForFolder = False
End Function
With that in place, I just needed to link that function into a routine that can use it…
Rolling the Final Routine
I write a lot of VBA, so this was pretty quick to knock up for me. The code itself looks like this:
Sub UpdatePQ()
Dim vFolder As Variant
Dim wsParameters As Worksheet
Dim wsData As Worksheet
'Set the worksheets
Set wsParameters = Worksheets("Parameters")
Set wsData = Worksheets("Data")
'Update the folder to import
vFolder = BrowseForFolder
If CStr(vFolder) = "False" Then
'No folder chosen, exit the routine
Exit Sub
End If
'Update parameter table with folder
wsParameters.Range("B2").Value = vFolder
wsData.Range("A1").ListObject.QueryTable.Refresh BackgroundQuery:=False
End Sub
In short, this routine basically:
- Sets references to the two worksheets
- Prompts the user for the folder. The output here could be a folder path or “False” which means the user cancelled. If it’s “False” we bail out
- If the path was provided, it gets placed in B2 of the Parameter worksheet (which is the “Value” field for the “File Path” variable. (So if you didn’t create your table starting in A1, then you’d need to update this.)
- Finally, we refresh the Power Query output table which I landed in cell A1 of the Data worksheet.
Final Setup Step
The very last step is to link the UpdatePQ macro to a button. This is fairly straight forward as well, and the steps are illustrated well in the Refresh Power Query with VBA post.
Make Power Query Prompt for a Folder at Refresh
And now, the only thing we need to do is click a button…
Choose a folder…
And the query will refresh the data in the landing page.
Try it out
You can download the completed workbook, as well as two folders with the source data, from my Skydrive. Click here to do so.
Caveats
I hope it goes without saying that the data structure of the files in the selected folders must be the same. If they’re not, the query load will fail, of course. But so long as you’re just trying to deal with different months/years, this should work nicely.
The post Prompt for a Folder at Refresh appeared first on The Ken Puls (Excelguru) Blog.