How do you INSERT a range from Excel to an SQL table - sql

I am using an old macro that sends a defined range from Excel to an MS Access database, and would like to adapt it to send to an SQL Server database.
Old Code (works very well, I am not the author):
'ExportAccess
Dim db As DAO.Database
Dim Rst As DAO.Recordset
Dim localMDB As String 'this is the address of the access mdb, removed from this snippit
sht = ActiveCell.Worksheet.Name
With Worksheets(sht)
.Range("L1:A" & .Range("A65536").End(xlUp).Row).Name = "Range"
End With
Set db = OpenDatabase(ActiveWorkbook.FullName, False, False, "excel 8.0")
db.Execute "INSERT INTO myTable IN '" & localMDB & "' SELECT * FROM [Range]", dbFailOnError
My attempt at modification:
Dim db As DAO.Database 'sql database
Dim rs As DAO.Recordset
Dim bd As DAO.Database 'excel sheet?
Dim Rst As DAO.Recordset
Set db = OpenDatabase("myDatabase", dbDriverNoPrompt, False, "ODBC;DATABASE=DB_Backup;DSN=myDatabase")
sht = ActiveCell.Worksheet.Name
With Worksheets(sht)
.Range("B1:A" & .Range("A65536").End(xlUp).Row).Name = "Range"
End With
db.Execute "INSERT INTO myTable SELECT * FROM [Range]", dbFailOnError
When I run my attempt, it gives the error that my "range" is not defined.
Any help would be greatly appreciated, thanks!

The reason the first code block worked successfully is that you connected to the Microsoft Access Jet/ACE Engine which can query Access database tables, Excel workbooks, even CSV text files. Notice how db is set directly to an Excel workbook and the append query externally interfaces to an Access database. This syntax is only supported with the Jet/ACE Engine.
However, in second code block you are connecting to an external database, namely SQL Server, and not the Jet/ACE Engine. Therefore, the analogous syntax is not supported. Specifically, as error indicates, [Range] does not exist because you are not connected to a workbook. You will need to specify all cell data of the range in VBA for appropriate data migration. Do not conflate SQL Server with MS Office even though they are products of same company.
Consider ADO (rather than DAO) for parameterization of values. Be sure to explicitly name columns in append SQL query. While your actual range is uncertain, below loops down the first column of range and uses .Offset to walk across the columns in current row. Adjust SQL, range limits, parameters, and types to align to actual data.
Sub SQLServerAppend()
' ADD REFERENCE FOR Microsoft ActiveX Data Objects #.# Library
Dim con As ADODB.Connection, cmd As ADODB.Command
Dim cell As Range
Dim strSQL As String
Set con = New ADODB.Connection
con.Open "DSN=myDatabase"
' PREPARED STATEMENT WITH QMARK PLACEHOLDERS
strSQL = "INSERT INTO myTable (Col1, Col2, Col3, ...) " _
& " VALUES (?, ?, ?, ...)"
sht = ActiveCell.Worksheet.Name
With Worksheets(sht)
For Each cell In .Range("A1", .Range("A1").End(xlDown))
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = con
.CommandText = strSQL
.CommandType = adCmdText
' BIND PARAMETERS WITH ? IN SQL (ALIGN VALUES TO ADO TYPES)
' FIRST COLUMN OF ROW RANGE
.Parameters.Append .CreateParameter("col1param", adVarChar, adParamInput, , cell.Offset(0, 0).Value)
' SECOND COLUMN OF ROW RANGE
.Parameters.Append .CreateParameter("col2param", adDate, adParamInput, , cell.Offset(0, 1).Value)
' THIRD COLUMN OF ROW RANGE
.Parameters.Append .CreateParameter("col3param", adDecimal, adParamInput, , cell.Offset(0, 2).Value)
'... ADD OTHER COLUMNS
' RUN APPEND ACTION
.Execute
End With
Next cell
con.Close
Set cmd = Nothing: Set con = Nothing
End Sub

I've modified my code with the loop from #Parfait to make it work for me. As my DAO connection was working I decided to stick with it.
Sub ToDbase()
'Modified by ployer. This sends values from an exel spreadsheet to your sql database
'with code from Parfait https://stackoverflow.com/questions/71817166/how-do-you-insert-a-range-from-excel-to-an-sql-table
Dim db As DAO.Database 'sql database
Dim rs As DAO.Recordset
Set db = OpenDatabase("myDB", dbDriverNoPrompt, False, "ODBC;DATABASE=myDB_Backup;DSN=myDB")
Dim cell As Range
Dim Value1 As String 'First value to import
Dim Value2 As String 'Second value to import. Add more as needed with the correct types
Dim i As Integer 'for testing in my exel sheet before trying in db
Dim n As Integer 'for testing in my exel sheet before trying in db
i = 1
n = 1
sht = ActiveCell.Worksheet.Name
With Worksheets(sht)
For Each cell In .Range("A1", .Range("A1").End(xlDown))
Value1 = cell.Offset(0, 0).Value 'Assign to variable "Value1" the value stored in Cell at position 0,0 (First time through would be A1)
Value2 = cell.Offset(0, 1).Value 'Assign to variable "Value2" the value stored in Cell at position 0,0 (First time through would be B1)
'For testing if iteration works.
'Cells(i, 5).Value = Value1
'Cells(n, 6).Value = Value2
'i = i + 1
'n = n + 1
'each time we go through the loop the Value1 and Value2 get sent to Col1 and Col2 in myTable. You need to define the value of Col1, for instance, if in the db it is called Customer it needs to be written Customer here.
db.Execute "INSERT INTO myTable (Col1, Col2) Values ('" & Value1 & "','" & Value2 & "') ", dbFailOnError
Next cell
End With
End Sub

Related

query a named single cell range vba

I am trying to select a single cell value in an excel spreadsheet named "AtwickShortfall" as follow
StrSql = "SELECT AtwickShortfall FROM [" & Glob_WsheetNameTradeLogOpsActions & "$AtwickShortfall]"
obviously does not work; can someone tell me the correct syntax ?
AtwickShortfall cell value is the sum of other values in the speadsheet; there are no tables in this spreadsheet at all.
UPDATE 1
tried this syntax
StrSql = "SELECT [AtwickShortfall] FROM [" & Glob_WsheetNameTradeLogOpsActions & "$]"
I get an error "No value given for one or more required parameters"
UPDATE 2
after amending my code as per #Dick Kusleika answer I now have this code
StrSql = "SELECT * FROM [AtwickShortfall]" ' & Glob_WsheetNameTradeLogOpsActions & "$AH34]"
Debug.Print (StrSql)
Set RecSet = ConnObj.Execute(StrSql)
If Not (RecSet Is Nothing) Then
With RecSet
If Not (.BOF) And Not (.EOF) Then
Debug.Print RecSet.Fields(0).Value
Else
'UdtKpi.HornInjMeterSum = 0
End If
End If
End With
End If
no errors but the recodset is empty (BOF is true); the value of AtwickShortfall is a formula that gives 0 at the moment. I also tried to remove the formula and fill the cell with 0 but same result: recordset BOF is true
UPDATE 3
I found a solution but please have a look at the screenshot below
cell AtwickShortfall is the one that I have now added a value of 125 on the column AH why this code work ?
StrSql = "SELECT Atw FROM [Operational_Actions$AH33:AH34]"
why it recognize the "atw" as a header of the range I gave??
If I change the above query to
StrSql = "SELECT Atw FROM [Operational_Actions$AH34:AH34]"
I get an epty recordset; It does not make sense how excel works to me; note that I have not implemented the worksheet data, it has been given to me
I think because the named range is at the workbook level (rather than worksheet level) that you can't specify what worksheet it's on. It's looking for a worksheet level named range when you specify the worksheet. This worked for me.
Sub getcell()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=\\99991-dc01\99991\dkusleika\My Documents\testadonamedrange.xlsx;Extended Properties=""Excel 12.0 Xml;HDR=NO"";"
Set rs = cn.Execute("select * from [AtwickShortfall]")
Debug.Print rs.Fields(0).Value
rs.Close
cn.Close
Set rs = Nothing
Set cn = Nothing
End Sub

INSERT INTO query in VBA

Im using Access 2013 and Excel 2013. In terms of References, I am using Microsoft Office 15.0 Access database engine Object Library.
So I am trying to run an INSERT INTO query from VBA. The worksheet has a list of part numbers, which I used this code to convert into an array.
Function partArray()
Dim partList() As Variant
Dim partArr(10000) As Variant
Dim x As Long
partList = ActiveWorkbook.Worksheets("Parts").ListObjects("Parts").ListColumns("Part Number").DataBodyRange.Value
For x = LBound(partList) To UBound(partList)
partArr(x) = partList(x, 1)
Next x
partArray = partArr
End Function
Now I am trying to use an INSERT INTO query to input these part numbers into a table in access. Any idea how I can do this?
You should use ADO to connect between Excel and Access. It will be a reference under Tools/References in the VBE. Using ADO you can run SQL statements. You can define your table in Excel as the origin table and then read data from that, put them into a recordset and then write the recordset into an Access table. There are plenty of examples on the internet. You can start with this: https://www.exceltip.com/import-and-export-in-vba/export-data-from-excel-to-access-ado-using-vba-in-microsoft-excel.html
Whoa! I think your approach is totally wrong. Try something like this.
Sub ADOFromExcelToAccess()
' exports data from the active worksheet to a table in an Access database
' this procedure must be edited before use
Dim cn As ADODB.Connection, rs As ADODB.Recordset, r As Long
' connect to the Access database
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0; " & _
"Data Source=C:\FolderName\DataBaseName.mdb;"
' open a recordset
Set rs = New ADODB.Recordset
rs.Open "TableName", cn, adOpenKeyset, adLockOptimistic, adCmdTable
' all records in a table
r = 3 ' the start row in the worksheet
Do While Len(Range("A" & r).Formula) > 0
' repeat until first empty cell in column A
With rs
.AddNew ' create a new record
' add values to each field in the record
.Fields("FieldName1") = Range("A" & r).Value
.Fields("FieldName2") = Range("B" & r).Value
.Fields("FieldNameN") = Range("C" & r).Value
' add more fields if necessary...
.Update ' stores the new record
End With
r = r + 1 ' next row
Loop
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub
Or, this.
Sub DAOFromExcelToAccess()
' exports data from the active worksheet to a table in an Access database
' this procedure must be edited before use
Dim db As Database, rs As Recordset, r As Long
Set db = OpenDatabase("C:\FolderName\DataBaseName.mdb")
' open the database
Set rs = db.OpenRecordset("TableName", dbOpenTable)
' get all records in a table
r = 3 ' the start row in the worksheet
Do While Len(Range("A" & r).Formula) > 0
' repeat until first empty cell in column A
With rs
.AddNew ' create a new record
' add values to each field in the record
.Fields("FieldName1") = Range("A" & r).Value
.Fields("FieldName2") = Range("B" & r).Value
.Fields("FieldNameN") = Range("C" & r).Value
' add more fields if necessary...
.Update ' stores the new record
End With
r = r + 1 ' next row
Loop
rs.Close
Set rs = Nothing
db.Close
Set db = Nothing
End Sub
Of course you could use the TransferSpreadsheet method if you want.
Option Explicit
Sub AccImport()
Dim acc As New Access.Application
acc.OpenCurrentDatabase "C:\Users\Public\Database1.accdb"
acc.DoCmd.TransferSpreadsheet _
TransferType:=acImport, _
SpreadSheetType:=acSpreadsheetTypeExcel12Xml, _
TableName:="tblExcelImport", _
Filename:=Application.ActiveWorkbook.FullName, _
HasFieldNames:=True, _
Range:="Folio_Data_original$A1:B10"
acc.CloseCurrentDatabase
acc.Quit
Set acc = Nothing
End Sub

Excel table to Access query connection, [Microsoft][ODBC Microsoft Access Drive] too few parameters. expected 1

I'm trying to create a table in Excel, which takes data from Access Query. I'm unable to find this query listed under Data->From Access. I'm using Data->From Other Sources -> From Data connection Wizard -> ODBC DSN. On final step it throws error [Microsoft][ODBC Microsoft Access Drive] too few parameters. expected 1.
I will not post full query at this moment, it is long
I will post subquery part (with some formatting) , that already throws this error. Can someone take a look and pinpoint where is the problem.
All queries I have work properly in Access. But I need the results export to Excel, as whole reporting VBA tool is there. (I know I can make SELECT INTO and create table, but it is not as elegant and simple to update) Thank you all for your time. Have a nice day
SELECT
Employees.PersNo,
Employees.Employee_name,
Employees.Reporting_Month,
Employees.Gender_Key,
Employees.Start_Date,
Employees.Business_Unit,
Employees.Position_ID,
Employees.Position,
Employees.Local_Band,
Employees.PS_Group,
Employees.Wage_Amount,
val(Employees.Bonus) AS [Bonus_%],
val([Employees].[Commissions_(%)]) AS [Commisions_%],
Employees.Wage_type, Employees.Wkhrs,
Q1.Business_Unit,
Q1.Position_ID,
Q1.Position,
Q1.Local_Band,
Q1.PS_Group,
Q1.Wage_Amount,
[Q1].[Bonus_%],
[Q1].[Commisions_%],
Employees.Wage_type,
Employees.Wkhrs,
Employees.Evid_Status
FROM Employees LEFT JOIN (SELECT
Dateadd("m",1,[Employees.Reporting_Month]) AS Reporting_Month,
Employees.PersNo,
Employees.Local_Band,
Employees.PS_Group,
Employees.Wage_Amount,
val(Employees.Bonus) AS [Bonus_%],
val([Employees].[Commissions_(%)]) AS [Commisions_%],
Employees.Wage_type, Employees.Wkhrs,
Employees.Business_Unit,
Employees.Position_ID,
Employees.Position,
Employees.Evid_Status
FROM Employees WHERE Employees.Evid_Status=1 ) AS Q1
ON (Employees.Reporting_Month = [Q1].[Reporting_Month]) AND (Employees.PersNo = [Q1].[PersNo])
WHERE Employees.Evid_Status=1;
Because Position is a reserved word in MS Accces, simply escape the word in both outer query and subquery with backticks or square brackets.
Interestingly, while the table alias qualifier works for reserved words inside the MSAccess.exe GUI program, external ODBC calls like from Excel may fail without escaping such reserved words:
SELECT
...
Employees.[Position],
...
SELECT
...
Employees.`Position`,
...
You can use Excel to query Access, like you see in the link below.
http://translate.google.pl/translate?js=n&prev=_t&hl=pl&ie=UTF-8&layout=2&eotf=1&sl=pl&tl=en&u=http%3A%2F%2Fafin.net%2FKsiazkaSQLwExcelu%2FGraficznyEdytorZapytanSqlNaPrzykladzieMsQuery.htm
Also, consider using a parameter query to do the export from Access to Excel.
Dim dbs As DAO.Database
Dim qdfTemp As DAO.QueryDef
Dim strSQL As String, strQDF As String
Set dbs = CurrentDb
' Replace NameOfTableOrQuery with the real name of the table or query,
' replace NameOfForm with the real name of the form, and replace
' ADateControlOnForm and AnotherDateControlOnForm with the real names
' of the controls on that form
strSQL = "SELECT NameOfTableOrQuery.* FROM NameOfTableOrQuery " & _
"WHERE NameOfTableOrQuery.FieldName >= " & _
Format(Forms!NameOfForm!ADateControlOnForm.Value,"\#mm\/dd\/yyyy\#") & _
" And NameOfTableOrQuery.FieldName <=" & _
Format(Forms!NameOfForm!AnotherDateControlOnForm.Value,"\#mm\/dd\/yyyy\#") & "';"
strQDF = "_TempQuery_"
Set qdfTemp = dbs.CreateQueryDef(strQDF, strSQL)
qdfTemp.Close
Set qdfTemp = Nothing
' Replace C:\MyFolderName\MyFileName.xls with the real path and filename for the
' EXCEL file that is to contain the exported data
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, _
strQDF,"C:\MyFolderName\MyFileName.xls"
dbs.QueryDefs.Delete strQDF
dbs.Close
Set dbs = Nothing
Or...write data from a record set in 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
Or, simply import the data 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
Having the same error - linking Excel and Access.
After changing double quotes to single quotes the error "too few parameters. expected 1" was resolved. The sample of correct code.
AND all_clean.lastapp='Dial'

Excel VBA checking if range of values exist in ODBC connected database

I am having an issue (otherwise I wouldn't be here) :)
In Excel I have a list of item numbers that need to be checked if they already exist in a database. At the moment the only way to do that is to run a query in a separate sheet to get all the item numbers (400,000+) which takes quite some time and has to be done each time.
I have started a vba query which goes through each cell that is selected and checks that value to see if it exist in the database. If it exist, the cell turns Red. If it doesn't exist, the cell turns green.
I'm not that great when it comes to querying databases using VBA so I used bits and pieces that I found online.
When I go to test it, Excel crashes and closes so I can't determine where its going wrong.
Public Sub CheckItemNoExist()
Dim DB As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim c As Range
Dim ItemNum As Variant
Dim bFound As Boolean
DB.Open "DSN=DBNAME;UID=****;PWD=****;"
Set rs = DB.OpenRecordset("SELECT [Inventory.ITM_NO] FROM [OAUSER.Inventory] WHERE [Inventory.ITM_NO]=" & ItemNum & ";", dbOpenDynaset)
For Each c In ActiveSheet.Selection
ItemNum = c.Value
bFound = Not rs.EOF
If bFound Then
c.Interior.Color = RGB(255, 0, 0)
Else
c.Interior.Color = RGB(0, 255, 0)
End If
Next
rs.Close
Set rs = Nothing
DB.Close
Set DB = Nothing
End Sub
Thank you!
Matt
I suggest you use an IN in your where clause to bring over all the items in the selection, then filter the recordset for each item to see if it found it. I don't have your data setup, so I used a truck database that I have handy. You should be able to convert
Sub CheckTruckExists()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim sSql As String
Dim aInClause() As String
Dim rCell As Range
Dim vaTrucks As Variant
Dim i As Long
'Open a connection to the database
Set cn = New ADODB.Connection
cn.Open sCONNECTIONSTRING
'Get an array of values from the selection
vaTrucks = Selection.Value
'Increase the size of the one-dimensional array to match
ReDim aInClause(LBound(vaTrucks, 1) To UBound(vaTrucks, 1))
'Fill a one-dim array from the two-dim array so we can Join it
For i = LBound(vaTrucks, 1) To UBound(vaTrucks, 1)
aInClause(i) = vaTrucks(i, 1)
Next i
'Build the SQL statement and execute it
sSql = "SELECT ReportTruck FROM qryTrucks WHERE ReportTruck IN ('" & Join(aInClause, "','") & "')"
Set rs = New Recordset
Set rs = cn.Execute(sSql)
'Loop through the selected cells
For Each rCell In Selection.Cells
'clear the filter, then refilter the recordset on the filtered value
rs.Filter = adFilterNone
rs.Filter = "ReportTruck = '" & rCell.Value & "'"
'If the filter returned zero records, it's eof
If rs.EOF Then
rCell.Interior.Color = RGB(255, 0, 0)
Else
rCell.Interior.Color = RGB(0, 255, 0)
End If
Next rCell
End Sub
My ReportTruck field is a String, so I have to enclose all the trucks in my IN clause with single quotes. If you're looking for something other than a String, modify the Join to accommodate that data type.
Also, there's no error checking to makes sure the Selection is actually a Range object or that it contains more than one cell - both are necessary to avoid an error.

Filtering a Million Records to 100,000 from two different sources

I have a project where I want to automate the reporting of a stupidly large set of data in Excel VBA. Basically I have a 1,000,000+ record database that I want to pull ~100,000 records from. The only way I have the 100,000 items is in an excel sheet, and I can't dump it into the same database to filter or into a temp table on the same server.
Is there a way to treat the Excel spreadsheet values as a database and call it within the SQL query in the VBA? I'd prefer not to use a loop because the database response is already poor enough as it is.
Ideas?
Thanks.
Edit - My assumption of "looping being bad" is incorrect according to one comment. Is this true? Would looping through the ID's have to poll the database 100,000 times or does it treat it as a single data pull?
You can use ADODB if you want to query within your workbook using sql like syntax.
I have included a sub to as an example of how to do this. You could call said sub like below:
Call queryTable("select top 100000 * from [Sheet6$A1:AI31]", range("Sheet5!A1"))
This would query data located in the range Sheet6$A1:AI31 (the first row being the headers) and would dump the data starting with the top left cell being Sheet5!A1.
Sub queryTable(sqlStr As String, destination As Range)
Dim strFile As String
Dim stADO As String
Dim cnt As ADODB.Connection
Dim recordcount As Long
Dim fieldcount As Long
Dim resultrange As Range
Dim mydestination As Range
strFile = ThisWorkbook.FullName
'connection string may need to be altered a little bit depending on your excel version
stADO = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strFile _
& ";Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1"";"
Set cnt = New ADODB.Connection
'Running query
With cnt
.CursorLocation = adUseClient
.Open stADO
.CommandTimeout = 0
Set rst = .Execute(sqlStr)
End With
Set mydestination = destination.Cells(1, 1).Offset(1, 0)
'Copying data (not headers) to destination
mydestination.CopyFromRecordset rst
'Setting some important variables
recordcount = rst.recordcount
fieldcount = rst.Fields.Count
Set range_collection = Range(mydestination.Cells(1, 1).Offset(-1, 0), mydestination.Cells(1, 1).Offset(recordcount - 1, fieldcount - 1))
'Copying the headers
For i = 0 To fieldcount - 1
mydestination.Cells(1, 1).Offset(-1, i).value = rst.Fields(i).name
Next i
'Closing everything down
cnt.Close
Set cnt = Nothing
End Sub