VBA大SQL-Query - 对象'Range'的方法'CopyFromRecordset'失败

时间:2016-01-07 09:07:00

标签: sql-server excel oracle vba excel-vba

下面发布的代码连接到oracle数据库,处理SQL查询并将结果表保存在新工作簿中。它可以很好地工作到大约200,000行。但是,对于较大的数据集,当我尝试将数据从记录集对象复制到工作簿时,会发生对象“范围”的错误方法'CopyFromRecordset'

dataWs.Range("A2").CopyFromRecordset dataset 

有什么解决方案吗?我尝试循环遍历数据集的所有元素并将它们复制到工作表中,但是对于大数据集来说这需要非常长的时间。你有什么想法?我感谢您的帮助!这是现在的代码:

Sub QueryExecute(sqlString, userPW, userID, serverName)
'Connect to database <serverName> using user name <userID> and 
'password <userPW> to process SQL query <sqlString> and save the
'query result in a new workbook

   Dim ConnStr As String
   Dim Cn As ADODB.Connection
   Dim dataset As ADODB.Recordset
   Dim dataWs As Worksheet
   Dim dataWb As Workbook
   Dim icols As Integer

   'Create new workbook that will hold the query result/table:
   Set dataWb = Excel.Application.Workbooks.Add
   Set dataWs = dataWb.Sheets(1)

   Application.Calculation = xlManual

   'Trim trailing/leading blanks from sqlString:
   sqlString = Trim(sqlString)

   'Create string for database connection:
   ConnStr = "UID=" & userID & ";PWD=" & userPW & ";DRIVER={Microsoft ODBC for Oracle};" _
                    & "SERVER=" & serverName & ";"

   'Connect to database:
   Set Cn = New ADODB.Connection

   On Error Resume Next 'Error handling in case connection does not work

   With Cn
     .ConnectionString = ConnStr
     .CursorLocation = adUseClient
     .Open
   End With

   'Error handling for failed connection:
   If Err.Number <> 0 Then

     dataWb.Close
     MsgBox "Connection to database failed. Check username and password."
     Exit Sub

   End If

   'Send SQL query to database:
   Set dataset = Cn.Execute(sqlString)

   'Error handling for failed query:
   If Err.Number <> 0 Then

     dataWb.Close
     MsgBox "SQL-query could not be processed."
     Exit Sub

   End If

   On Error GoTo 0

   'Copy column names in first row of table worksheet:
   For icols = 0 To dataset.Fields.count - 1
     dataWs.Cells(1, icols + 1).Value = dataset.Fields(icols).Name
   Next

   dataWs.Range(dataWs.Cells(1, 1), _
   dataWs.Cells(1, dataset.Fields.count)).Font.Bold = True 'Format column names

   'Copy data to workbook:
   '***THIS WILL FAIL FOR LARGE DATASETS***
   dataWs.Range("A2").CopyFromRecordset dataset 


   dataset.Close
   Cn.Close

   MsgBox "Query successful."

   Application.Calculation = xlCalculationAutomatic

End Sub

2 个答案:

答案 0 :(得分:1)

根据Microsoft article - 最大行数为1,048,576行,共16,384列。 鉴于,操纵或审查一百万行是不现实的 - 我们可以假设电子表格是汇总行吗? 如果是这种情况 - 您应该始终寻求最小化返回到Excel的记录集的大小。为此,您可以将数据的处理/汇总卸载到数据库中。

这可以在SQL查询或返回SYS_REFCURSOR的数据库过程中完成。这实际上是指向结果集的指针。

答案 1 :(得分:1)

与@OraNob一样,通过在数据库端进行过滤,聚合和排序,最大限度地减少您返回的数据量。如果必须检索大型数据集(以减少多个调用),则可以考虑保持记录集处于打开状态,只需使用各种数据子集所需的数据填充工作表。 如果您的记录集的行数超过百万行,那么您可以将结果写入多个工作表。

我还建议使用GetRows函数,您需要对其进行转置,因为GetRows数组的大小将按列然后排成行,而Excel最适合行然后列。

另外,考虑到数据集的大小,并假设32位Office,您无法依靠Application.Worksheet.Transpose进行转置,因为您可能已经用完了记忆,如果你自己进行转置,你可能需要小心记忆。考虑将转置和插入分成几批。

最后,请记住将工作表中的插入作为范围进行,因为它将比逐个单元格更多更快。例如:

Dim aData(1 to 10000, 1 to 16)
aRecordset = rst.GetRows(10000)
'Transpose the aRecordset into aData
'...
Sheet1.Range(Sheet1.cells(1,1),Sheet1.Cells(10000,16) = aData