5

I am trying to perform an ADODB query on a named range in an Excel 2013 workbook.

My code is as follows:

Option Explicit
Sub SQL_Extract()
    Dim objConnection           As ADODB.Connection
    Dim objRecordset            As ADODB.Recordset
    Set objConnection = CreateObject("ADODB.Connection")        ' dataset query object
    Set objRecordset = CreateObject("ADODB.Recordset")          ' new dataset created by the query

    objConnection.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                                     "Data Source=" & ThisWorkbook.FullName & ";" & _
                                     "Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1"";"
    objConnection.Open

    objRecordset.Open "SELECT * FROM [HighRange]", objConnection, adOpenStatic, adLockOptimistic, adCmdText

    If Not objRecordset.EOF Then
        ActiveSheet.Cells(1, 1).CopyFromRecordset objRecordset
    End If

    objRecordset.Close
    objConnection.Close
End Sub

If the range HighRange extends beyond row 65536 (e.g. A65527:B65537) I get an error message enter image description here

If I remove enough rows to drop the range below row 65536, the code works.

The code also works if I force the workbook to be read-only (and ensure that no-one else has a non-read-only version open).

Is this something I am doing wrong, or is this a bug in Excel 2013?

(Problem exists in both 32-bit and 64-bit versions. Also exists in Excel 2016.)

YowE3K
  • 23,852
  • 7
  • 26
  • 40
  • 1
    I'm going to guess that you found an instance with MSoft forgot to change an `int` into a `long` in their MS Access db engine code... Sounds like a bug to me. Try it in XL2016? – David Colwell Jul 29 '16 at 03:47
  • Unfortunately it's a work situation, so we are just going to Excel 2013. (I don't think we had the issue in Excel 2010.) – YowE3K Jul 29 '16 at 03:48
  • 4
    http://forum.chandoo.org/threads/excel-recordset-only-returns-65536-rows-if-you-try-to-pull-data-from-a-range.12492/ – Tim Williams Jul 29 '16 at 04:35
  • Definitely appears to be an `int` vs `long` issue as 65,535 is the largest unsigned 16-bit integer. – Alexis Olson Jul 29 '16 at 04:44
  • After reading the link posted by @TimWilliams, I thought that I had found a workaround - by copying the range to a new worksheet (ensuring the destination area starts in row 1), activating that worksheet, running the query against that worksheet's data (without using a range name), and then deleting the temporary worksheet afterwards - but it doesn't work reliably as it loses information from some of the rows, so I am back to looking for suggestions re answers. – YowE3K Jul 29 '16 at 07:43
  • Have you checked, if the file is saved in the correct format (xlsx, xlsm)? Not likely to be issue, but worth a try. – Mister 832 Jul 29 '16 at 11:02
  • @Mister832 - File is an xlsm file. I noticed that Extended Properties can use "Excel 12.0 Macro", or "Excel 12.0 xlm" as well as the "Excel 12.0" that I am using, but neither of those correct the problem. – YowE3K Jul 29 '16 at 18:06
  • @DavidColwell I just bought myself a personal copy of Excel 2016 - tested the code there and the problem remains. – YowE3K Jun 13 '17 at 19:52

2 Answers2

1

I haven't been able to find an actual answer to my problem, so the best work-around I could come up with is to create an extra workbook, copy my range to a sheet in that workbook (starting at cell A1), save that workbook, and then use that workbook/worksheet as the source of the query.

(I originally thought I could get away with just creating a temporary worksheet in the existing workbook, i.e. without creating a temporary workbook, but problems occur if the user has two instances of Excel active - the Connection.Open event re-opens the workbook in the first instance of Excel, even though we are running the macros in the second instance, and therefore the re-opened workbook doesn't have the dummy worksheet in it. And I don't want to save a copy of the existing workbook with a dummy sheet in it.)

Sub SQL_Extract_Fudged()
    Dim objConnection           As ADODB.Connection
    Dim objRecordset            As ADODB.Recordset
    Dim wsOrig As Worksheet
    Dim wbTemp As Workbook
    Dim wbTempName As String
    Dim wsTemp As Worksheet

    Set wsOrig = ActiveSheet

    'Generate a filename for the temporary workbook
    wbTempName = Environ$("TEMP") & "\TempADODBFudge_" & Format(Now(), "yyyymmdd_hhmmss") & ".xlsx"
    'Create temporary workbook
    Set wbTemp = Workbooks.Add
    'Use first sheet as the place for the temporary copy of the range we want to use
    Set wsTemp = wbTemp.Worksheets(1)
    wsTemp.Name = "TempADODBFudge"
    'Copy the query range to the temporary worksheet
    wsOrig.Range("HighRange").Copy Destination:=wsTemp.Range("A1")
    'Save and close the temporary workbook
    wbTemp.SaveAs wbTempName
    wbTemp.Close False
    'Get rid of references to the temporary workbook
    Set wsTemp = Nothing
    Set wbTemp = Nothing

    'Create connection and recordset objects
    Set objConnection = CreateObject("ADODB.Connection")
    Set objRecordset = CreateObject("ADODB.Recordset")

    'Create the connection string pointing to the temporary workbook
    objConnection.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                                     "Data Source=" & wbTempName & ";" & _
                                     "Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1"";"
    objConnection.Open

    'Perform the query against the entire temporary worksheet
    objRecordset.Open "SELECT * FROM [TempADODBFudge$]", objConnection, adOpenStatic, adLockOptimistic, adCmdText

    'Copy output (for this example I am just copying back to the original sheet)
    If Not objRecordset.EOF Then
        wsOrig.Cells(1, 1).CopyFromRecordset objRecordset
    End If

    'Close connections
    objRecordset.Close
    objConnection.Close

    'Get rid of temporary workbook
    On Error Resume Next
    Kill wbTempName
    On Error GoTo 0

End Sub

I would still prefer a more robust solution to this problem, so would love someone else to come up with another answer.

YowE3K
  • 23,852
  • 7
  • 26
  • 40
0

Well, in case this is still an open issue, I had the same problem and solved it by not specifying any row numbers in the range being queried. Example:

I was trying to query [SheetName$A1:W100000], which gave me exactly the same error you had. I then specified the range as [SheetName$A:W] and it weeerks!

Hope this helps!

Rascio
  • 61
  • 6