parameterized queries in Excel with SQLite ODBC - excel

I'm using the SQLite ODBC Driver v0.9993 in Excel 2016 (win10). The main impetus for using an external source is that I have too much data for Excel to sanely manage, so it will be pulled based on user-selected criteria. Because of this, I'd like to use parameterized queries based on the contents of well-defined worksheet cells.
I'm trying two methods:
Straight VBA, where I do something like this (rough code):
Sub UpdateTables()
Dim ws as Worksheet
Dim adoCN As ADODB.Connection
Dim adoCmd As ADODB.Command
Dim adoRS As ADODB.Recordset
Dim sDB as String
Dim rCell as Range
Set adoCN = New ADODB.Connection
Set adoRS = New ADODB.Recordset
' ws is set to correct worksheet
' ...
' define sDB from worksheet cell
With adoCN
.Open "Provider=MSDASQL.1;Persist Security Info=True;" _
& "Driver={SQLite3 ODBC Driver};" _
& "Database=" & sDB & ";" _
& "DSN=SQLite3 Datasource;LongNames=true;fksupport=true", "", "" '
End With
Set adoCmd = New ADODB.Command
adoCmd.ActiveConnection = adoCN
' rCell points to cell containing query parameter
Set adoParam = adoCmd.CreateParameter(, adVarChar, adParamInput, _
Len(rCell.value), rCell.value)
adoCmd.Parameters.Append adoParam
adoCmd.CommandText = "SELECT * FROM TableName WHERE X = ?"
adoRS.Open Source:=adoCmd, CursorType:=adOpenKeyset
With ws.ListObjects(1).QueryTable
Set .RecordSet = adoRS
.Refresh ' errors with "Error 1004: invalid accessor flag"
End With
End Sub
(Code has been simplified, generally I include sanity checks.)
GUI-based in Excel, with New Query > From Other Sources > From ODBC, set DSN to "SQLite3 Datasource", and enter in the Connection string used above.
Unfortunately, the "Parameters" button (Connections > select query > Properties > Definition tab) is grayed out.
I think I prefer the second solution, but neither is working at the moment.

Rather than opening recordset via an ADO connection, you need to execute the command from ADO command object. This an often discussed topic of recordset .execute vs .open. Of course, be sure to add error handling to capture relevant errors/exceptions.
Sub UpdateTables()
On Error GoTo ErrHandle
Dim ws as Worksheet
Dim adoCN As New ADODB.Connection, adoRS As New ADODB.Recordset
Dim adoCmd As New ADODB.Command
Dim sDB as String
Dim rCell as Range
'Set ws = ... '
'sDB = ... '
' DATABASE CONNECTION '
adoCN.Open "Provider=MSDASQL.1;Persist Security Info=True;" _
& "Driver={SQLite3 ODBC Driver};" _
& "Database=" & sDB & ";" _
& "DSN=SQLite3 Datasource;LongNames=true;fksupport=true", "", ""
' ADO COMMAND '
With adoCmd
.ActiveConnection = adoCN
.CommandText = "SELECT * FROM TableName WHERE X = ?"
.CommandType = adCmdText
.Parameters.Append .CreateParameter(, adVarChar, adParamInput, _
Len(rCell.value), rCell.value)
End With
' EXECUTE RECORDSET '
Set adoRS = adoCmd.Execute
' DEFINE QUERYTABLE '
With ws.ListObjects(1).QueryTable
Set .RecordSet = adoRS
.Refresh
End With
' CLOSE AND FREE RESOURCES '
adoRS.Close: adoCN.Close
Set adoRS = Nothing: Set adoCmd = Nothing: Set adoCN = Nothing
Exit Sub
ErrHandle:
MsgBox Err.Number & " - " & Err.Description
Set adoRS = Nothing: Set adCmd = Nothing: Set adCN = Nothing
Exit Sub
End Sub

Related

Import from closed workbook in order of sheets ADODB

As to me, ADODB is something new for me that I am eager to learn. Here's a code that I tried my best but needs your ideas to make it appear more professional and more efficient. The problem in the code is that the data is grabbed from sheets in reverse order and not in the order of sheets. To make it clear, I have Sample.xlsx workbook with two sheets Sheet1 and New and the code is supposed to loop through t he sheets then search for specific header then to get the data from such a column. All this with the ADO approach. the code grabs the data from New sheet first then from Sheet1 .. While the order of the sheets is Sheet1 then New >> another point, how can I close the recordset properly. I mean is using .Close is enough or I have to set it to Nothing Set rs=Nothing.
Sub ImportFromClosedWorkbook()
Dim e, ws As Worksheet, cn As ADODB.Connection, rs As ADODB.Recordset, rsHeaders As ADODB.Recordset, b As Boolean, sFile As String, shName As String, strSQL As String, iCol As Long
sFile = ThisWorkbook.Path & "\Sample.xlsx"
'shName = "Sheet1"
Dim rsData As ADODB.Recordset
Set cn = New ADODB.Connection
cn.Open ConnectionString:="Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" & sFile & "';" & "Extended Properties=""Excel 12.0;HDR=YES;IMEX=1;"";"
'--------
Set ws = ThisWorkbook.ActiveSheet
Set rs = cn.OpenSchema(20)
Do While Not rs.EOF
sName = rs.Fields("Table_Name")
If Right(sName, 14) <> "FilterDatabase" Then
sName = Left(sName, Len(sName) - 1)
'Debug.Print sName
b = False
strSQL = "SELECT * FROM [" & sName & "$]"
Set rsHeaders = New ADODB.Recordset
rsHeaders.Open Source:=strSQL, ActiveConnection:=cn, Options:=1
For iCol = 0 To rsHeaders.Fields.Count - 1
'Debug.Print rsHeaders.Fields(iCol).Name
For Each e In Array("Ref No", "Reference", "Number")
If e = rsHeaders.Fields(iCol).Name Then
b = True: Exit For
End If
Next e
If b Then Exit For
Next iCol
If b Then
'Debug.Print e
strSQL = "SELECT [" & e & "] FROM [" & sName & "$]"
Set rsData = New ADODB.Recordset
Set rsData = cn.Execute(strSQL)
ws.Range("A" & ws.Cells(Rows.Count, 1).End(xlUp).Row + 1).CopyFromRecordset rsData
rsData.Close
'here I am stuck of how to get the data from the found column
End If
'rs.Close
End If
rs.MoveNext
Loop
'rs.Close
'------------------
' strSQL = "SELECT * FROM [" & shName & "$]"
' Set rs = New ADODB.Recordset
' Set rs = cn.Execute(strSQL)
' Range("A1").CopyFromRecordset rs
rs.Close: Set rs = Nothing
cn.Close: Set cn = Nothing
End Sub
the code grabs the data from New sheet first then from Sheet1 .. While the order of the sheets is Sheet1 then New
The tab order is an Excel feature. The Sheet names are extracted in alphabetical order when you use ADODB. This is the reason why you get New sheet first and then Sheet1.
Note: If the sheet names start with number or have spaces then they are given a priority first. Few examples
Example 1
Sheets names: 1, Sheet1, 1Sheet4, She et3, Sheet5
Returned as
'1$'
'1Sheet4$'
'She et3$'
Sheet1$
Sheet5$
Example 2
Sheets names: Sheet2, Sheet5, She et3, Sheet1, Sheet4
Returned as
'She et3$'
Sheet1$
Sheet2$
Sheet4$
Sheet5$
Example 3
Sheets names: 1, Sheet1, 2, Sheet2, 3, Sheet3
Returned as
'1$'
'2$'
'3$'
Sheet1$
Sheet2$
Sheet3$
Alternative to ADODB
If you want to extract the names of the sheets in the tab order then you can use DAO as shown by Andrew Poulsom in THIS link. Posting the code here in case the link dies...
Sub GetSecondSheetName()
' Requires a reference to Microsoft DAO x.x Object Library
' Adjust to suit
Const FName As String = "P:\Temp\MrExcel\Temp\SheetNames.xls"
Dim WB As DAO.Database
Dim strSheetName As String
Set WB = OpenDatabase(FName, False, True, "Excel 8.0;")
' TableDefs is zero based
strSheetName = WB.TableDefs(1).Name
MsgBox strSheetName
WB.Close
End Sub
Close is enough or I have to set it to Nothing Set rs=Nothing.
No you do not have to set it to nothing. VBA cleans it automatically when it exits the prodecure. But yes it is a good practice to flush the toilet.
Interesting Read:
You may want to read the post by #GSerg in the below link...
When should an Excel VBA variable be killed or set to Nothing?
For it to work with XLSX, use this (Requires a reference to Microsoft Office XX.XX Access database engine Object Library)
Option Explicit
'~~> Change this to the relevant file name
Const FName As String = "C:\Users\routs\Desktop\Delete Me later\TEXT.XLSX"
Sub Sample()
'Requires a reference to Microsoft Office XX.XX Access database engine Object Library
Dim db As DAO.Database
Set db = OpenDatabase(FName, False, False, "Excel 12.0")
Dim i As Long
For i = 0 To db.TableDefs.Count - 1
Debug.Print db.TableDefs(i).Name
Next i
db.Close
End Sub
In Action
#Siddharth Rout you have inspired me how to search for such new topic for me and I could use such a code to list all the worksheets in the order of tab using DAO but with late binding ( I am curious to know how to use early binding as I tried but with no success)
Sub Get_Worksheets_Using_DAO()
Dim con As Object, db As Object, sName As String, i As Long
Set con = CreateObject("DAO.DBEngine.120")
sName = ThisWorkbook.Path & "\Sample.xlsx"
Set db = con.OpenDatabase(sName, False, True, "Excel 12.0 XMl;")
For i = 0 To db.TableDefs.Count - 1
Debug.Print db.TableDefs(i).Name
Next i
db.Close: Set db = Nothing: Set con = Nothing
End Sub

Excel - receiving run-time error 1004 ODBC Error

I am pretty unfamiliar with VB code and trying to solve an issue. Several users can run this macro fine, but some get a Run-time error 1004, General ODBC error. Debug points to the last line below. It is odd to me that it is setup to connect simply to a directory of a file share. Anyone know what may be going on? I have verified they have access to the share.
Option Explicit
Sub CreatePolicyTable()
Dim qryTable As QueryTable
Dim rngDestination As Range
Dim strConnection As String
Dim strSQL As String
Dim strParam1 As String
Dim strParam3 As String
Worksheets("Pol Data").Range("A1:A1048576").EntireRow.ClearContents
Call Delete_Named_Ranges
'Define the connection string and destination range.
strConnection = "ODBC;Driver={Microsoft Text Driver (*.txt; *.csv)};" & _
"DBQ=\\My Folder\;" & _
"Extensions=asc,csv,tab,txt;"
Set rngDestination = Sheet2.Range("A1")
'Create the SQL string.
strSQL = "SELECT * FROM My_File.csv"
'set the parameter strings
strParam1 = " WHERE state = '" & Sheet5.ComboBox1.Text & "'"
strParam3 = " ;"
'check & build variable parameters depending on whether combobox ticked by user
strSQL = strSQL & strParam1 & strParam3
'Create the QueryTable.
Set qryTable = Sheet2.QueryTables.Add(strConnection, rngDestination)
'Populate the QueryTable.
qryTable.CommandText = strSQL
qryTable.CommandType = xlCmdSql
qryTable.BackgroundQuery = False
qryTable.Refresh
'Create Named Ranges
ActiveWorkbook.Names.Add Name:="PolData", RefersToR1C1:= _
"=OFFSET('Pol Data'!R1C1,0,0,COUNTA('Pol Data'!C1),COUNTA('Pol Data'!R1))"
End Sub
Sub Refresh_All()
Call CreatePolicyTable
Worksheets("Competitive Analysis").PivotTables("1").PivotCache.Refresh
Worksheets("Competitive Analysis").Activate
End Sub
Sub Delete_Named_Ranges()
Dim wbBook As Workbook
Dim nName As Name
Set wbBook = ActiveWorkbook
For Each nName In wbBook.Names
nName.Delete
Next nName
End Sub

Not able to pull records from access to excel, Probable connection issue

I using the below code to pull records from access to excel.
I am getting error at
connDB.Open ConnectionString:="Provider = Microsoft.ACE.OLEDB.12.0; data source=" & strDB
The error says"invalid sql statement, delete, insert,procedure,selet or update"
Kindly help as I am stuck and cannot move forward at all....
please help.
Sub automateAccessADO_9()
'Using ADO to Import data from an Access Database Table to an Excel worksheet (your host application).
'refer Image 9a to view the existing SalesManager Table in MS Access file "SalesReport.accdb".
'To use ADO in your VBA project, you must add a reference to the ADO Object Library in Excel (your host application) by clicking Tools-References in VBE, and then choose an appropriate version of Microsoft ActiveX Data Objects x.x Library from the list.
'--------------
'DIM STATEMENTS
Dim strMyPath As String, strDBName As String, strDB As String, strSQL As String
Dim i As Long, n As Long, lFieldCount As Long
Dim rng As Range
'instantiate an ADO object using Dim with the New keyword:
Dim adoRecSet As New ADODB.Recordset
Dim connDB As New ADODB.Connection
'--------------
'THE CONNECTION OBJECT
strDBName = "Computer.accdb"
strMyPath = ThisWorkbook.Path
strDB = strMyPath & "\" & strDBName
'Connect to a data source:
'For pre - MS Access 2007, .mdb files (viz. MS Access 97 up to MS Access 2003), use the Jet provider: "Microsoft.Jet.OLEDB.4.0". For Access 2007 (.accdb database) use the ACE Provider: "Microsoft.ACE.OLEDB.12.0". The ACE Provider can be used for both the Access .mdb & .accdb files.
connDB.Open ConnectionString:="Provider = Microsoft.ACE.OLEDB.12.0; data source=" & strDB
'--------------
'OPEN RECORDSET, ACCESS RECORDS AND FIELDS
Dim ws As Worksheet
'set the worksheet:
Set ws = ActiveWorkbook.Sheets("Sheet1")
'Set the ADO Recordset object:
Set adoRecSet = New ADODB.Recordset
'Opening the table named SalesManager:
strTable = "memory"
'--------------
'COPY RECORDS FROM ALL FIELDS OF A RECORDSET:
'refer Image 9d to view records copied to Excel worksheet
adoRecSet.Open Source:=strTable, ActiveConnection:=connDB, CursorType:=adOpenStatic, LockType:=adLockOptimistic
Set rng = ws.Range("A1")
lFieldCount = adoRecSet.Fields.Count
For i = 0 To lFieldCount - 1
'copy column names in first row of the worksheet:
rng.Offset(0, i).Value = adoRecSet.Fields(i).Name
adoRecSet.MoveFirst
'copy record values starting from second row of the worksheet:
n = 1
Do While Not adoRecSet.EOF
rng.Offset(n, i).Value = adoRecSet.Fields(i).Value
adoRecSet.MoveNext
n = n + 1
Loop
Next i
'select column range to AutoFit column width:
Range(ws.Columns(1), ws.Columns(lFieldCount)).AutoFit
'worksheet columns are deleted because this code is only for demo:
Range(ws.Columns(1), ws.Columns(lFieldCount)).Delete
adoRecSet.Close
'close the objects
connDB.Close
'destroy the variables
Set adoRecSet = Nothing
Set connDB = Nothing
End Sub
When going from Access to Excel, you have quite a few options!
Here's one way to EXPORT data from Access to Excel.
Dim lngColumn As Long
Dim xlx As Object, xlw As Object, xls As Object, xlc As Object
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim blnEXCEL As Boolean, blnHeaderRow As Boolean
blnEXCEL = False
' Replace True with False if you do not want the first row of
' the worksheet to be a header row (the names of the fields
' from the recordset)
blnHeaderRow = True
' Establish an EXCEL application object
On Error Resume Next
Set xlx = GetObject(, "Excel.Application")
If Err.Number <> 0 Then
Set xlx = CreateObject("Excel.Application")
blnEXCEL = True
End If
Err.Clear
On Error GoTo 0
' Change True to False if you do not want the workbook to be
' visible when the code is running
xlx.Visible = True
' Replace C:\Filename.xls with the actual path and filename
' of the EXCEL file into which you will write the data
Set xlw = xlx.Workbooks.Open("C:\Filename.xls")
' Replace WorksheetName with the actual name of the worksheet
' in the EXCEL file
' (note that the worksheet must already be in the EXCEL file)
Set xls = xlw.Worksheets("WorksheetName")
' Replace A1 with the cell reference into which the first data value
' is to be written
Set xlc = xls.Range("A1") ' this is the first cell into which data go
Set dbs = CurrentDb()
' Replace QueryOrTableName with the real name of the table or query
' whose data are to be written into the worksheet
Set rst = dbs.OpenRecordset("QueryOrTableName", dbOpenDynaset, dbReadOnly)
If rst.EOF = False And rst.BOF = False Then
rst.MoveFirst
If blnHeaderRow = True Then
For lngColumn = 0 To rst.Fields.Count - 1
xlc.Offset(0, lngColumn).Value = rst.Fields(lngColumn).Name
Next lngColumn
Set xlc = xlc.Offset(1,0)
End If
' write data to worksheet
Do While rst.EOF = False
For lngColumn = 0 To rst.Fields.Count - 1
xlc.Offset(0, lngColumn).Value = rst.Fields(lngColumn).Value
Next lngColumn
rst.MoveNext
Set xlc = xlc.Offset(1,0)
Loop
End If
rst.Close
Set rst = Nothing
dbs.Close
Set dbs = Nothing
' Close the EXCEL file while saving the file, and clean up the EXCEL objects
Set xlc = Nothing
Set xls = Nothing
xlw.Close True ' close the EXCEL file and save the new data
Set xlw = Nothing
If blnEXCEL = True Then xlx.Quit
Set xlx = Nothing
Here's another way.
Dim lngColumn As Long
Dim xlx As Object, xlw As Object, xls As Object, xlc As Object
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Dim strPathFileName As String, strWorksheetName As String
Dim strRecordsetDataSource As String
Dim blnEXCEL As Boolean, blnHeaderRow As Boolean
blnEXCEL = False
' Replace C:\Filename.xls with the actual path and filename
' that will be used to save the new EXCEL file into which you
' will write the data
strPathFileName = "C:\Filename.xls"
' Replace QueryOrTableName with the real name of the table or query
' whose data are to be written into the worksheet
strRecordsetDataSource = "QueryOrTableName"
' Replace True with False if you do not want the first row of
' the worksheet to be a header row (the names of the fields
' from the recordset)
blnHeaderRow = True
' Establish an EXCEL application object
On Error Resume Next
Set xlx = GetObject(, "Excel.Application")
If Err.Number <> 0 Then
Set xlx = CreateObject("Excel.Application")
blnEXCEL = True
End If
Err.Clear
On Error GoTo 0
' Change True to False if you do not want the workbook to be
' visible when the code is running
xlx.Visible = True
' Create a new EXCEL workbook
Set xlw = xlx.Workbooks.Add
' Rename the first worksheet in the EXCEL file to be the first 31
' characters of the string in the strRecordsetDataSource variable
Set xls = xlw.Worksheets(1)
xls.Name = Trim(Left(strRecordsetDataSource, 31))
' Replace A1 with the cell reference of the first cell into which the
' headers will be written (blnHeaderRow = True), or into which the data
' values will be written (blnHeaderRow = False)
Set xlc = xls.Range("A1")
Set dbs = CurrentDb()
Set rst = dbs.OpenRecordset(strRecordsetDataSource, dbOpenDynaset, dbReadOnly)
If rst.EOF = False And rst.BOF = False Then
' Write the header row to worksheet
If blnHeaderRow = True Then
For lngColumn = 0 To rst.Fields.Count - 1
xlc.Offset(0, lngColumn).Value = rst.Fields(lngColumn).Name
Next lngColumn
Set xlc = xlc.Offset(1,0)
End If
' copy the recordset's data to worksheet
xlc.CopyFromRecordset rst
End If
rst.Close
Set rst = Nothing
dbs.Close
Set dbs = Nothing
' Save and close the EXCEL file, and clean up the EXCEL objects
Set xlc = Nothing
Set xls = Nothing
xlw.SaveAs strPathFileName
xlw.Close False
Set xlw = Nothing
If blnEXCEL = True Then xlx.Quit
Set xlx = Nothing
Here's a way to IMPORT date from Access to Excel.
Sub ADOImportFromAccessTable(DBFullName As String, _
TableName As String, TargetRange As Range)
' Example: ADOImportFromAccessTable "C:\FolderName\DataBaseName.mdb", _
"TableName", Range("C1")
Dim cn As ADODB.Connection, rs As ADODB.Recordset, intColIndex As Integer
Set TargetRange = TargetRange.Cells(1, 1)
' open the database
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & _
DBFullName & ";"
Set rs = New ADODB.Recordset
With rs
' open the recordset
.Open TableName, cn, adOpenStatic, adLockOptimistic, adCmdTable
' all records
'.Open "SELECT * FROM " & TableName & _
" WHERE [FieldName] = 'MyCriteria'", cn, , , adCmdText
' filter records
RS2WS rs, TargetRange ' write data from the recordset to the worksheet
' ' optional approach for Excel 2000 or later (RS2WS is not necessary)
' For intColIndex = 0 To rs.Fields.Count - 1 ' the field names
' TargetRange.Offset(0, intColIndex).Value = rs.Fields(intColIndex).Name
' Next
' TargetRange.Offset(1, 0).CopyFromRecordset rs ' the recordset data
End With
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub
Here's one more way to IMPORT your data.
Sub DAOCopyFromRecordSet(DBFullName As String, TableName As String, _
FieldName As String, TargetRange As Range)
' Example: DAOCopyFromRecordSet "C:\FolderName\DataBaseName.mdb", _
"TableName", "FieldName", Range("C1")
Dim db As Database, rs As Recordset
Dim intColIndex As Integer
Set TargetRange = TargetRange.Cells(1, 1)
Set db = OpenDatabase(DBFullName)
Set rs = db.OpenRecordset(TableName, dbOpenTable) ' all records
'Set rs = db.OpenRecordset("SELECT * FROM " & TableName & _
" WHERE " & FieldName & _
" = 'MyCriteria'", dbReadOnly) ' filter records
' write field names
For intColIndex = 0 To rs.Fields.Count - 1
TargetRange.Offset(0, intColIndex).Value = rs.Fields(intColIndex).Name
Next
' write recordset
TargetRange.Offset(1, 0).CopyFromRecordset rs
Set rs = Nothing
db.Close
Set db = Nothing
End Sub

How do I copy and filter a DAO recordset in VBA?

Due to problems with DAO (see my previous question), I need to create an Excel VBA Recordset from an Access query and filter its results using a user-defined function.
I thought I could use the following code to accomplish this:
Sub test()
Dim db As Database
Dim rs As Recordset
Dim rs_clone As Recordset
Set db = OpenDatabase(dbPath)
Set rs = db.OpenRecordset("select testVal from dataTable")
Set rs_clone = rs.Clone
rs_clone.MoveLast
rs_clone.MoveFirst
while not rs_clone.eof
if myUDF(rs_clone!testVal) then
rs_clone.delete
end if
rs_clone.moveNext
wend
End Sub
But that actually deletes values from my source table, so the clone isn't a new recordset that I can freely alter, it's just another pointer to the original one. How can I use my UDF to filter out the records I don't want, while leaving the original data untouched, if putting the UDF in the query itself is not an option?
In Access with DAO, this is how you'd do it:
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim rsFiltered As DAO.Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset("SELECT tblInventory.* FROM tblInventory;")
rs.MoveLast
Debug.Print "Unfiltered: " & rs.RecordCount
rs.filter = "[LastUpdated]>=#1/1/2011#"
Set rsFiltered = rs.OpenRecordset
rsFiltered.MoveLast
Debug.Print "Filtered: " & rsFiltered.RecordCount
rsFiltered.Close
Set rsFiltered = Nothing
rs.Close
Set rs = Nothing
Set db = Nothing
However, note that (as mentioned in the help file), it may be just as fast to simply reopen the recordset with new criteria, instead of filtering the existing recordset.
Use the .getrows method:
Dim rs_clone As Variant
...
rs_clone = rs.getrows(numrows)
then process the resulting 2-d array.
Option Compare Database
Private Sub Command0_Click()
Sub Export_Click()
Dim db As Database, rs As Recordset, sql As String, r As Variant
Dim appExcel As Excel.Application
Dim excelWbk As Excel.Workbook
Dim excelSht As Object
Dim rng As Excel.Range
Set appExcel = New Excel.Application
On Error Resume Next
Set excelWbk = appExcel.Workbooks.Open("Folder Name(Template)")
Set db = CurrentDb()
sql1 = "Select * from Query_New"
sql2 = "Select * from Query_Expired"
Set rs1 = db.OpenRecordset(sql1, dbReadOnly)
Set rs2 = db.OpenRecordset(sql2, dbReadOnly)
Dim SheetName1 As String
Dim SheetName2 As String
SheetName1 = "New"
SheetName2 = "Expired"
'For first sheet
On Error Resume Next
excelWbk.Sheets(SheetName1).Select
If Err.Number <> 0 Then
MsgBox Err.Number
excelWbk.Close False
appExcel.Quit
Exit Sub
End If
With excelWbk.Activesheet
.Cells(5, 1).CopyFromRecordset rs1
On Error GoTo 0
End With
'For second sheet
On Error Resume Next
excelWbk.Sheets(SheetName2).Select
If Err.Number <> 0 Then
MsgBox Err.Number
excelWbk.Close False
appExcel.Quit
Exit Sub
End If
With excelWbk.Activesheet
.Cells(5, 1).CopyFromRecordset rs2
On Error GoTo 0
End With
rs1.Close
Set rs1 = Nothing
rs2.Close
Set rs2 = Nothing
db.Close
Set db = Nothing
On Error Resume Next
excelWbk.SaveAs "C:\Documents and settings\" & Environ("UserName") & "\Desktop\Decision.xlsx"
If Err.Number <> 0 Then
MsgBox Err.Number
End If
excelWbk.Close False
appExcel.Quit
Set appExcel = Nothing
MsgBox "The report has been saved"
End Sub
End Sub

How do I access an Excel named table via ADO/ODBC?

I have a workbook with multiple sheets, and have created Named Tables (NOT ranges) in the work book. For illustrative purposes, these table names are tblA, tblB, and tblC. I am unable to find a way to query these tables via ADO or ODBC. I can access named ranges, but this will not work for my needs.
Thanks!
I don't know if it can be done directly but will be interested to see if anyone comes back with a working method. The GetSchema collection of ADO only seems to pick up sheetnames and named ranges but not ListObjects which named tables are. Below is a workaround but it means opening Excel to find the header/data range of the table. It's almost pointless using ADO or similar then as you can copy the data directly but I suppose you could convert to a named range before saving as a one-off task?
Option Explicit
Sub test()
Dim WB As Workbook, WS As Worksheet, strExcelfile As String, strSheetName As String
Dim strTableName As String, objListObj As ListObject, HeaderRange As String
Dim strSQL As String, DataRange As String
strExcelfile = "C:\Users\osknows\Desktop\New folder\test.xlsm"
strSheetName = "Sheet1"
strTableName = "TableName"
Set WB = GetObject(strExcelfile) 'Filepath & Filename
Set WS = WB.Sheets(strSheetName) 'SheetName
Set objListObj = WS.ListObjects(strTableName) 'Table Name
'get range of Table
HeaderRange = objListObj.HeaderRowRange.Address
DataRange = objListObj.DataBodyRange.Address
'write data directly if required
With ThisWorkbook
With Sheet1
'.Range(HeaderRange).Value = WS.Range(HeaderRange).Value
'.Range(DataRange).Value = WS.Range(DataRange).Value
End With
End With
'or use ADODB which is a bit pointless now!
Dim cnn1 As New ADODB.Connection
Dim rst1 As New ADODB.Recordset
cnn1.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & strExcelfile & ";" & _
"Extended Properties=""Excel 12.0;HDR=No;IMEX=1"";"
strSQL = "SELECT * FROM [" & strSheetName & "$" & Replace(DataRange, "$", "") & "];"
rst1.Open strSQL, cnn1, adOpenStatic, adLockReadOnly
'tidy up
Set objListObj = Nothing
Set WS = Nothing
WB.Close
Set WB = Nothing
End Sub

Resources