I've created a connection to an oData feed in a macro, without saving "Queries" or "Connections" in the workbook, so that it will hopefully defer oData authentication to the built in Excel mechanisms. Basically I want to do the following in a VBA macro:
The reason for not wanting to just create queries manually with the GUI is because this macro is going to exist in an .XLAM (add-in) therefore saving queries in the add-in's workbook causes a security prompt when Excel starts, and I'm trying to just make the same behaviour as if you were to use XMLHTTP or similar
I have this so far:
Public Sub Test()
On Error GoTo handler
Dim s As String
Dim c As WorkbookConnection
Dim q As WorkbookQuery
Dim t As QueryTable
Dim ws As Worksheet
Application.StatusBar = "Creating Query..."
s = "let " & _
"Source = OData.Feed(""" & URL & """, null, [Implementation=""2.0""]), " & vbCrLf & _
"ES_ATTRIBUTE_SPECIFICATION_table = Source{[Name=""ES_ATTRIBUTE_SPECIFICATION"",Signature=""table""]}[Data], " & vbCrLf & _
"#""Removed Other Columns"" = Table.SelectColumns(ES_ATTRIBUTE_SPECIFICATION_table,{""OBJECT_SPECIFICATION""}), " & vbCrLf & _
"#""Removed Duplicates"" = Table.Distinct(#""Removed Other Columns""), " & vbCrLf & _
"#""Sorted Rows"" = Table.Sort(#""Removed Duplicates"",{{""OBJECT_SPECIFICATION"", Order.Ascending}}) " & vbCrLf & _
"in " & vbCrLf & _
"#""Sorted Rows"""
Set q = ThisWorkbook.Queries.Add(Name:=QUERY_NAME, Formula:=s)
'Application.StatusBar = "Creating Connection..."
'Set c = ThisWorkbook.Connections.Add2( _
' CONN_NAME, _
' "", _
' "OLEDB;Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=" & QUERY_NAME & ";Extended Properties="""";", _
' "SELECT * FROM [ES_ATTRIBUTE_SPECIFICATION]", _
' xlCmdSql) 'This prevents "invalid procedure call or argument"
'c.OLEDBConnection.BackgroundQuery = False
Application.StatusBar = "Creating Data Table..."
Set ws = shtODataDump
Set t = shtODataDump.QueryTables.Add( _
"OLEDB;Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=" & QUERY_NAME & ";Extended Properties="""";", _
ws.Range("A1"), _
"SELECT * FROM [ES_ATTRIBUTE_SPECIFICATION]")
t.Refresh False '1004 - [Expression.Error] The import ES_ATTRIBUTE_SPECIFICATION matches no exports. Did you miss a module reference?
normalexit:
On Error Resume Next
If Not c Is Nothing Then
c.Delete
End If
If Not q Is Nothing Then
q.Delete
End If
If Not ws Is Nothing Then
ws.QueryTables.Item(TABLE_NAME).Delete
End If
Application.StatusBar = ""
Exit Sub
handler:
Debug.Print Err.Number & " - " & Err.Description
Resume normalexit
End Sub
The problem I'm facing is that when I refresh the QueryTable I get 1004 - [Expression.Error] The import ES_ATTRIBUTE_SPECIFICATION matches no exports. Did you miss a module reference?
and I can't find an answer as to what that actually means..?
What am I doing wrong?
I might come up against other things but I got to a point where I want to share a solution. The working code is:
Private Const QUERY_NAME = "MY_COOL_QUERY"
Public Sub Test()
On Error GoTo handler
Dim s As String
Dim c As WorkbookConnection
Dim q As WorkbookQuery
Dim t As QueryTable
Dim ws As Worksheet
Application.StatusBar = "Creating Query..."
s = "let " & _
"Source = OData.Feed(""" & URL & """, null, [Implementation=""2.0""]), " & vbCrLf & _
"ES_ATTRIBUTE_SPECIFICATION_table = Source{[Name=""ES_ATTRIBUTE_SPECIFICATION"",Signature=""table""]}[Data], " & vbCrLf & _
"#""Removed Other Columns"" = Table.SelectColumns(ES_ATTRIBUTE_SPECIFICATION_table,{""OBJECT_SPECIFICATION""}), " & vbCrLf & _
"#""Removed Duplicates"" = Table.Distinct(#""Removed Other Columns""), " & vbCrLf & _
"#""Sorted Rows"" = Table.Sort(#""Removed Duplicates"",{{""OBJECT_SPECIFICATION"", Order.Ascending}}) " & vbCrLf & _
"in " & vbCrLf & _
"#""Sorted Rows"""
Set q = ThisWorkbook.Queries.Add(Name:=QUERY_NAME, Formula:=s)
Application.StatusBar = "Creating Data Table..."
Set ws = shtODataDump
Set t = shtODataDump.QueryTables.Add( _
"OLEDB;Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=" & QUERY_NAME & ";Extended Properties="""";", _
ws.Range("A1"), _
"SELECT * FROM [" & QUERY_NAME & "]")
t.Refresh BackgroundQuery:=False
normalexit:
On Error Resume Next
If Not c Is Nothing Then
c.Delete
End If
If Not q Is Nothing Then
q.Delete DeleteConnection:=True
End If
If Not ws Is Nothing Then
ws.QueryTables.Item(TABLE_NAME).Delete
End If
Application.StatusBar = ""
Exit Sub
handler:
Debug.Print Err.Number & " - " & Err.Description
Resume normalexit
End Sub
This runs the query against oData and puts the result in A1 on a sheet. A Connection object is created automatically when creating WorkbookQuery, but this can be deleted along with the Query by doing q.Delete DeleteConnection:=True
where q
is the query
Edit: Doing this also creates named ranges automatically, which can also be programmatically deleted