Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance EXCELVBA-一种快速循环一系列范围的方法。查找_Performance_Vba_Excel - Fatal编程技术网

Performance EXCELVBA-一种快速循环一系列范围的方法。查找

Performance EXCELVBA-一种快速循环一系列范围的方法。查找,performance,vba,excel,Performance,Vba,Excel,我正在执行一个类似于数据库的“类联接”操作,在这个数据库中,我有两个不同的数据集a和B,它们有一些共同的标识符,我们称之为“id”。我的目标是创建第三个数据集C,它由连接id的a和B的交集组成 SELECT a.id, a.some_column, b.another_column FROM a,b WHERE a.id = b.id 我可以在Excel中通过在A的id列中的所有行上循环并执行一个范围来执行相同的操作。为A中的每一行查找B的id列。类似如下: For Each r in

我正在执行一个类似于数据库的“类联接”操作,在这个数据库中,我有两个不同的数据集a和B,它们有一些共同的标识符,我们称之为“id”。我的目标是创建第三个数据集C,它由连接id的a和B的交集组成

SELECT a.id, a.some_column, b.another_column 
FROM a,b 
WHERE a.id = b.id 
我可以在Excel中通过在A的id列中的所有行上循环并执行一个范围来执行相同的操作。为A中的每一行查找B的id列。类似如下:

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,我能找到的最接近的问题是,但我并不真正理解最佳答案,我也不确定它是否适用于我的场景。

您尝试使用。 这将允许您使用示例中的简单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
这种方法对你来说可能有点新,但我确信它是有效的,而且它确实很快,尽管我没有实际比较速度。 了解和检查链接的连接字符串。 顺便说一句,您可以将数据源设置到运行宏的同一工作簿中

例如:


其中有A和B页以及另一张C页作为输出。HTH.

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

因此,您应该像这样重构代码:

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
将整个工作表合并到一个数组中 将整个工作表吞并到一个数组中 像现在一样执行for循环工作,但在这些数组上,并写入第三个数组 将整个第三个数组放入工作表中 这是通过使用变体阵列完成的,如下所述:

在标有“在单个操作中读取和写入大块数据”的部分中

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

当然,如果您的表太大,您可能会有内存问题,但是对于今天的RAM大小,它们必须非常非常大才能成为问题