VBA - 比较 2 张纸中的 2 tables,并在另一张纸中得到结果以创建比较 table

VBA - to compare 2 tables from 2 sheets, and get result in another sheets creating comparison table

这超出了我的可能性。 我知道如何使用 Vlookup 或 Hlookup 创建 Vba 代码以进行单一比较。然而,我正在尝试的是我所不知道的。

我需要比较 2 tables。第一个是要求,第二个是数据库提取。 table 都包含相同的“操作”列和其他雇主角色为 header 的列。两个 table 的 Action 列中的值相同,但顺序不同(这些值需要充当主键)。 雇主角色为 header 的列 - 两个 table 的 header 值相同 - 但列的顺序不同。

作为 header 的雇主角色的列数量不是常量,每次我获取此文件时它都会发生变化。 extract 中的那些列的顺序与 requirements 中的顺序不同。 “操作”列(主键)中的值数量也不是常量,每次我收到文件时都会更改。所以我无法设置具体范围。

要求示例table 提取示例 table 预期的例子

  1. 需要在将创建比较 table 的位置创建新的目标工作表。
  2. VBA 在新创建的工作表中创建比较 table。 此 table 应具有“行动”列 + 所有雇主角色为 header 的列形成要求 + 所有雇主角色为 header 的列以与要求中的列相同的顺序提取集 + 比较table 比较来自 Requirements 和 Extract 的 Employers 角色之间的值,并显示值 YES 或 NO

请尝试下一个代码。它会在 return 中新建一个 sheet (在最后一个存在之后)。新文件名为“New Sheet”。如果存在,则清除并重新使用:

Sub testMatchTables()
 Dim sh As Worksheet, sh1 As Worksheet, shNew As Worksheet
 Dim tbl1 As ListObject, tbl2 As ListObject, rightH As Long
 Dim arrR, arrE, arrH1, arrH2, arrFin, i As Long, j As Long, k As Long
 Dim first As Long, sec As Long, refFirst As Long, refSec As Long
 
 Set sh = Set sh = Worksheets("Requirements")'use here the sheet keeping the first table
 Set sh1 = Worksheets("Extract Table") 'use here your appropriate sheet
 Set tbl1 = sh.ListObjects(1)  'use here your first table name (instead of 1)
 Set tbl2 = sh1.ListObjects(1) 'use here your second table name (instead of 1)
 arrR = tbl1.Range.value 'put the table range in an array
 arrE = tbl2.Range.value 'put the table range in an array
                         'working with arrays will condiderably increase the processing speed
 ReDim arrFin(1 To UBound(arrR), 1 To UBound(arrR, 2) * 3 + 2) 'redim the array to keep the processing result
                                                       'UBound is a property telling the number of array elements

 arrH1 = Application.Index(arrR, 1, 0) 'make a slice in the array (1D array), the first row, which keeps the headers
 arrH2 = Application.Index(arrE, 1, 0) 'make a slice in the array (1D array), the first row, which keeps the headers

 'build the column headers:
 For i = 1 To UBound(arrFin, 2)
    If i <= UBound(arrH1) Then  'firstly the headers of the first table are filled in the final array
        arrFin(1, i) = arrH1(i)
    ElseIf refSec = 0 Then  'refSec is the column where a blanck column will exist
        first = first + 1   'the code incrementes this variable to allow making empty only for the following row
        If first = 1 Then
            arrFin(1, i) = Empty: refFirst = i 'make the empty column between the two tables data and create a reference
                                               'to be decreated from the already incremented i variable
        Else
            arrFin(1, i) = arrH1(i - refFirst) 'place each header column values
            If i - refFirst = UBound(arrH1) Then refSec = i + 1 'when the code reaches the end of the first array
                                                                'it creates a reference for referencing the second time
        End If
    Else
        sec = sec + 1  'the same philosophy as above, to create the second empty column
        If sec = 1 Then
            arrFin(1, i) = Empty 'create the empty column (for each processed row)
        Else
            arrFin(1, i) = arrH1(i - refSec) 'fill the header columns
        End If
    End If
 Next

 Dim C As Long, r As Long, eT As Long, T As Long
 eT = UBound(arrR)            'mark the ending of the first array (where to be the first empty column)
 T = UBound(arrR, 2) * 2 + 2  'mark the begining of the third final array part
                              'after the second empty column
 For i = 2 To UBound(arrR)    'iterating between the first array rows
    For j = 2 To UBound(arrE) 'iterating the second array rows
        If arrR(i, 1) = arrE(j, 1) Then 'if the both arrays first column matches
             arrFin(i, 1) = arrR(i, 1): arrFin(i, T + 1) = arrR(i, 1) 'put the Action values in the first area columns
             arrFin(i, eT) = arrR(i, 1)   'put the Action values in the last area column
             For C = 2 To UBound(arrR, 2) 'iterate between the array columns
                rightH = Application.match(arrR(1, C), arrH2, 0) 'find the match of the first array header in the second one
                arrFin(i, C) = arrR(i, C): arrFin(i, C + eT - 1) = arrE(j, rightH) 'place the matching header in the final array
                If arrR(i, C) = arrE(j, rightH) Then
                    arrFin(i, T + C) = "TRUE"  'place 'TRUE' in case of matching
                Else
                    arrFin(i, T + C) = "FALSE" 'place 'FALSE' in case of NOT matching
                End If
             Next C
        End If
    Next j
 Next i
 On Error Resume Next    'necessary to return an error if worksheet "New Sheet" does not exist
  Set shNew = Worksheets("New Sheet")
  If err.Number = 9 Then 'if it raises error number 9, this means that the sheet does not exist
    err.Clear: On Error GoTo 0 'clear the error and make the code to return other errors, if any
    Set shNew = Worksheets.Add(After:=Worksheets(Worksheets.count)) 'set shNew as new inserted sheet
    shNew.name = "New Sheet"   'name the newly inserted sheet
  Else
    shNew.cells.Clear: On Error GoTo 0 ' in case of sheet exists, it is clear and the code is made to return errors
  End If
 'set the range where the final array to drop its values:
 With shNew.Range("A1").Resize(UBound(arrFin), UBound(arrFin, 2))
    .value = arrFin       'drop the array content
    .EntireColumn.AutoFit 'AutoFit the involved columns
 End With
End Sub

请测试它并发送一些反馈。

已编辑:

我尽可能详细地评论了代码。如果还有什么不清楚的地方,请不要犹豫,要求澄清。