
Post-processing Query output in Excel
The question behind this posting came from several different customers in the UK earlier in the month. The use case behind this is that customers want some additional control over what comes up in excel when running a query to excel without requiring the user to perform manual steps to accomplish this.
So, there are several options for accomplishing this, each with its own set of pros and cons. Here they are.
Pretty much all you need to know is covered in this blog posting.
Although this works relatively well to solve the problem, it has the following issues.
Scheduling the Query and using an App Engine Program
This approach has quite a few moving parts, and will not work if you want to run the queries to window. Here is my recommendation for doing this:
Add the macros to the client instead of the server.
This approach, I believe, is the easiest to put in place and has the most stability. The key to it working is that whenever excel opens up a spreadsheet, it will fire the auto-open macro in any add-ins that are part of the excel environment. Therefore, by creating an excel add-in with an auto-open macro in it, you can cause the macro to run when the query results are opened.
This sounds easy in practice. However, to be successfull, you need to test to see if the excel file came from query (where you do want to process it), or if it didn't (which means you don't want to touch it).
This is where the tricky part comes in. You see, because drilling was always a part of nVision, we stuffed additional metadata into the resulting file that allows us to do all sorts of cool things with it. However, with query, we never thought to do that (and one concern we had was about keeping the file as small as possible for sizing reasons). Now that I'm no longer running the group, I'm thinking that it would have been really nice to have put that feature in (if I had a time machine, I could probably go back and fix that... Does anybody have one I can borrow?)
Okay. So now we all have to workaround an oversight I had when I owned query. What's the best solution? Well, unfortunately, scheduled query and the online query (which is a servlet on the web server) have different formats of files. Here, let me illustrate.
Here's what it looks like when runnning query online (using the servlet). See if you can find the query name somewhere in the picture.

Now, here's what it looks like when running a query through scheduled query. Again, see if you can find the query name somewhere in the picture.

As you can see, the query name is not in the query results, but is in the title bar of the browser (if hosting in excel). This is a property that is not easily accessible in VBA (although we spent a lot of time and effort figuring that out for our product... you'll have to buy it to get that code from us, though ;-).
Our recommendation to you is to have a standard set of text that you include in your query result, such as a prefix in the query description (because the query description is always put in call A1 regardless of whether its run through scheduled query or online). If you want to put somebody else on the hook for making sure it works right all the time (and also get a lot of other cool features that would take a lot of work, such as drilling, subtotalling, and number formatting), we think our add-in would be a great fit.
Since we wrote this post (and due to requests from our customers), we ended up building this into our nVision add-in and changing the name of the product to be the "Grey Sparling Excel Add-in". The post processing we do is to apply formatting, such as number formatting, sizing of columns, freezing the coumn headings, applying auto-filters, and applying subtotals. This product also allows users to drill from their queries to pages or other pages. Here's the product page for it. Also, here's a flash demo of the product's features.


Public Declare Function GetActiveWindow Lib "user32" () As Long
Public Declare Function GetWindowText Lib "user32.dll" Alias
"GetWindowTextA" (ByVal hwnd As Long, ByVal lpstring As String, ByVal aint
As Long) As Long
Public Function w32apiLiveWdwTitle() As String
'retrieves window title
Dim charcount As Long
Dim lpstring As String
Dim strbuffer As Long
Dim hwnd as long
strbuffer = 300
lpstring = String$(strbuffer, Chr$(0))
hwnd = GetActiveWindow
If hwnd = 0 then exit sub
charcount = GetWindowText(hwnd, lpstring, strbuffer)
If charcount > 0 Then
w32apiWdwTitle = Left$(lpstring, charcount)
Else
w32apiWdwTitle = ""
End If
End Function