Excel VBA - 循环遍历一堆Range.Finds的更快方法

时间:2015-01-13 07:11:23

标签: performance vba excel-vba excel

我正在表演一个像#join; like'操作(类似于数据库),其中我有两个不同的数据集A和B,它们有一些共同的标识符(让我们称之为' id')。我的目标是创建第三个数据集C,它包含A和B的交集(连接id)。在SQL中,相应的查询类似于

SELECT a.id, a.some_column, b.another_column 
FROM a,b 
WHERE a.id = b.id 

我可以在Excel中执行相同的操作,循环遍历A< id id列中的所有行,并在A的每一行上对B&#39}的id列执行Range.Find这样的事情:

For Each r in Worksheet_A.Range(Cells(start_row_a,id_column_a),Cells(end_row_A,id_column_a))
    Set found = Worksheet_B.Range(Cells(start_row_b,id_column_b),Cells(end_row_b,id_column_b)).Find(r.Value)
    If Not found is Nothing Then
        ' write stuff to Worksheet_C, e.g. found.Value, found.Offset(0,1).Value, r.Offset(0,-1).Value, etc.
    End If
Next r

这很好用,但速度很慢。我知道像VB这样的语言中的显式循环非常慢。我的问题是:有更快的路吗?我错过了更好的实施吗?我在SO上找到的最接近的问题是here,但我并不是真正理解最佳答案,而且我不确定它是否适用于我的方案。

2 个答案:

答案 0 :(得分:0)

您尝试使用ADO (ActiveX Data Object) 这将允许您使用简单的SQL语句,如您的示例。

样品:

Sub ject()
    Dim con As Object: Set con = CreateObject("ADODB.Connection")
    Dim rec As Object: Set rec = CreateObject("ADODB.Recordset")
    Dim datasource As String
    datasource = "C:\Users\user.name\Desktop\TestFolder\Test.xlsx" 'change to suit

    Dim sconnect As String
    'Connection string used is for Excel 2007 and up
    sconnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                "Data Source=" & datasource & ";" & _
                "Extended Properties=""Excel 12.0;HDR=YES"";"
    con.Open sconnect

    Dim sqlstr As String

    sqlstr = "SELECT e.column1, u.column2, e.column3, e.column4 "
    sqlstr = sqlstr & "FROM [A$] e " 'from a sheet named A
    sqlstr = sqlstr & "INNER JOIN [B$] u " 'compare with a sheet named B
    sqlstr = sqlstr & "ON e.id = u.id " 
    sqlstr = sqlstr & "GROUP BY e.column1, u.column2, e.column3, e.column4 "

    rec.Open sqlstr, con, 3, 1

    Dim lrow As Long
    With Sheets("C") 'Change to suit
        .Range("A1").CopyFromRecordset rec
    End With

    rec.Close: con.Close
    Set rec = Nothing: Set con = Nothing
End Sub

这种方法对您来说可能有点新鲜,但我确定有效且确实很快(虽然我实际上没有比较速度)。
要了解XL 2003 and belowXL 2007 and up的连接字符串,请检查链接 顺便说一下,您可以将数据源设置为运行宏的同一工作簿。

示例:

datasource = ThisWorkbook.FullName

您可以在其中输出表格 A B 以及另一张图纸 C 。 HTH。

答案 1 :(得分:0)

加速此类事情的最重要方法是知道“VBA世界”和“工作表世界”之间的交互很慢,因此您应该将它们保持在最低限度。

所以你应该重构你的代码:

  1. 将整个WorksheetA表吞入一个数组
  2. 将整个WorksheetB表吞入一个数组
  3. 像现在一样进行循环工作,但是在那些数组上,写入第三个数组
  4. 将整个第三个数组放入工作表
  5. 这是使用变体数组完成的,如下所示:

    http://msdn.microsoft.com/en-us/library/ff726673.aspx#xlFasterVBA

    标记为:在单个操作中读取和写入大块数据

    重构比看起来容易,因为数组也采用行和列坐标,就像原始表一样。

    当然,如果你的桌子太大,你可能会遇到内存问题,但是对于今天的RAM大小,它们必须非常非常大,才能成为一个问题......