通过匹配两个工作表的列值来突出显示行中的差异

时间:2019-06-17 15:11:38

标签: excel vba

我从数据库检索数据到excel文件。如果我在数据库中进行了更改,并在excel文件中检索了一个新的“转储”,我想知道自上次检索数据以来进行了哪些更改。我对编码比较陌生,并且在这个问题上遇到了局限。我需要做的是比较名称/ ID与ws1的colum 1与ws2的colum 1中的匹配名称,并突出显示每行中ws2的差异。但是,随着新名称的添加/删除,该名称可能在每个转储之间位于不同的行中。

我尝试了一些仅比较每个单元格中的值的代码,如果名称/ ID与要比较的工作表在同一行位置,则这非常好。但是,如果名称在不同的行中,则该行下的整个数据集将被视为更改并突出显示。

Private Sub CommandButton1_Click()

Call compareSheets("Sheet1", "Sheet2")

End Sub

Sub compareSheets(shtSheet1 As String, shtSheet2 As String)

Dim mycell As Range
Dim mydiffs As Integer

    'For each cell in sheet2 that is not the same in Sheet1, color it yellow
For Each mycell In ActiveWorkbook.Worksheets(shtSheet2).UsedRange
    If Not mycell.Value = ActiveWorkbook.Worksheets(shtSheet1).Cells(mycell.Row, mycell.Column).Value Then

        mycell.Interior.Color = vbYellow
        mydiffs = mydiffs + 1


    End If

    'If the cell has a matching value change it to "no fill"
    If mycell.Value = ActiveWorkbook.Worksheets(shtSheet1).Cells(mycell.Row, mycell.Column).Value Then
        mycell.Interior.ColorIndex = 0
    End If
Next

    'msg to display no. of difference found
MsgBox mydiffs & " differences found", vbInformation

ActiveWorkbook.Sheets(shtSheet2).Select

End Sub

WORKSHEET 1
Tag         Temperature    Pressure
13L0001A1   40             20
13L0002A2   40             25
13L0003A3   35             25

WORKSHEET 2
Tag         Temperature    Pressure
13L0001A1   40             20
13L0002A2   45             20
13L0003A3   35             25

这是我要比较的数据集的示例。 (非常简化,我的实际数据集包含45个列)。我需要突出显示标签13L0002A2的温度和压力变化。

任何帮助都会得到高度赞赏!

编辑: 这是我要实现的新代码:

Public Sub comparesheets(shtSheet1 As String, shtSheet2 As String)

    Dim rowCount1 As Integer
    Dim rowCount2 As Integer

        rowCount1 = ThisWorkbook.Sheets(1).Range("D2").SpecialCells(xlCellTypeLastCell).Row
        rowCount2 = ThisWorkbook.Sheets(2).Range("D2").SpecialCells(xlCellTypeLastCell).Row

    Dim rng1 As Range
    Dim rng2 As Range

    Set rng1 = ThisWorkbook.Sheets(1).Range("D2:D" & rowCount1)
    Set rng2 = ThisWorkbook.Sheets(2).Range("D2:D" & rowCount2)

    Dim var As Variant, iSheet As Integer

    'Cycle through all the cells in that column:
    For rowCount1 = 4 To rng1
    Next rowCount1

    'For every cell that is not empty, search through the column "D" in each worksheet for the
    'value that matches that cell value in the workbook.
    If Not IsEmpty(Cells(rowCount1, 4)) Then
        For iSheet = ActiveSheet.Index + 4 To Worksheets.Count
        var = Application.Match(Cells(rng1, 4).Value, Worksheets(iSheet).Columns(4), 0)
        Next iSheet
    End If


    'If a matching value is found, then search each row for differences. If difference is found, color the cell yellow.
    'otherwise, continue searching until you reach the end of the workbook.
    If Not IsError(var) Then

        For Each rng1 In ActiveWorkbook.Worksheets(shtSheet1).UsedRange

                If Not rng2.Value = rng1.Value Then
                rng2.Interior.Color = vbYellow

                If Not rng2.Offset(0, 1).Value = rng1.Offset(0, 1).Value Then
                rng2.Offset(0, 1).Interior.Color = vbYellow

                End If
        ' Here i get an error with "Next without For"
        Next rng1

    End If


    ' If no match is found, color entire row yellow
    If IsError(var) Then
    EntireRow.Interior.Color = vbYellow

    End If

End Sub

如果我在For Each单元格后添加Next语句,则会显示一条错误,提示Next(无For)。如果我不添加Next语句,则会收到一条错误消息,提示“如果没有结束则阻止”。

对可能出什么问题的任何建议?

第二次编辑:

所以我尝试从https://docs.microsoft.com/en-us/office/vba/api/excel.worksheetfunction.match修改示例代码,因为这几乎可以满足我的需要。我一次成功地获得了代码。然后,我清除了所有格式,然后重试,并遇到下标超出范围的错误(“ 9”),我一生都无法找出为什么它只能工作一次,而不是现在。

我使用的代码:

Sub HighlightMatches()

    'Declare variables
    Dim var As Variant, iSheet As Integer, iRow As Long, iRowL As Long, bln As Boolean, rng1 As Range, rng2 As Range, rowCount1 As Integer, rowCount2 As Integer

        rowCount1 = ThisWorkbook.Sheets(1).Range("D4").SpecialCells(xlCellTypeLastCell).Row
        rowCount2 = ThisWorkbook.Sheets(2).Range("D4").SpecialCells(xlCellTypeLastCell).Row

        Set rng1 = ThisWorkbook.Sheets(1).Range("D4:D" & rowCount1)
        Set rng2 = ThisWorkbook.Sheets(2).Range("D4:D" & rowCount2)

       'Set up the count as the number of filled rows in the first column of Sheet1.
        iRowL = Cells(Rows.Count, 4).End(xlUp).Row

       'Cycle through all the cells in that column:
       For iRow = 4 To iRowL

          'For every cell that is not empty, search through the column "D" in each worksheet in the
          'workbook for a value that matches that cell value.
          If Not IsEmpty(Cells(iRow, 4)) Then
             For iSheet = ActiveSheet.Index + 1 To Worksheets.Count
                bln = False
                var = Application.Match(Cells(iRow, 4).Value, Worksheets(iSheet).Columns(4), 0)

                'If you find a matching value, indicate success by setting bln to true and exit the loop;
                'otherwise, continue searching until you reach the end of the workbook.
                If Not IsError(var) Then
                   bln = True
                   Exit For
                End If
             Next iSheet
          End If

          'If match is found, compare row for each colum;
          'if no match is found, color cell yellow.
          If Not bln = True Then
           For Each rng1 In ThisWorkbook.Worksheets(1).UsedRange
                If Not rng1.Value = ThisWorkbook.Worksheets(2).Cells(rng2.Row, 4) Then
                    rng1.Interior.ColorIndex = vbYellow
                End If
           Next rng1
          End If
       Next iRow
End Sub

2 个答案:

答案 0 :(得分:0)

未经测试:

Public Sub comparesheets(shtSheet1 As String, shtSheet2 As String)

    Dim ws1 As Worksheet, ws2 As Worksheet, c As Range, cTest As Range, cMatch As Range, m
    Set ws1 = ThisWorkbook.Sheets(1)
    Set ws2 = ThisWorkbook.Sheets(2)

    For Each c In ws1.Range(ws1.Range("D2"), ws1.Cells(ws1.Rows.Count, "D").End(xlUp)).Cells
        m = Application.Match(c.Value, ws2.Columns(4), 0)
        If Not IsError(m) Then
            'matched rows - compare values
            For Each cTest In Application.Intersect(c.EntireRow, ws1.UsedRange).Cells
                Set cMatch = ws2.Cells(m, cTest.Column)  '<<< EDIT
                If cTest.Value <> cMatch.Value Then
                    cMatch.Interior.Color = vbYellow
                End If
            Next cTest
        Else
            'no matched row
            c.EntireRow.Interior.Color = vbYellow
            Debug.Print "No match for '" & c.Value & "' (Row " & c.Row & ")"
        End If
    Next c

End Sub

答案 1 :(得分:0)

感谢TIm,这是我的问题的解决方案:


Private Sub CommandButton1_Click()

Call comparesheets("Sheet1", "Sheet2")

End Sub

Public Sub comparesheets(shtSheet1 As String, shtSheet2 As String)

   Dim ws1 As Worksheet, ws2 As Worksheet, c As Range, cTest As Range, cMatch As Range, m
    Set ws1 = ThisWorkbook.Sheets(1)
    Set ws2 = ThisWorkbook.Sheets(2)

    For Each c In ws1.Range(ws1.Range("D2"), ws1.Cells(ws1.Rows.Count, "D").End(xlUp)).Cells
        m = Application.Match(c.Value, ws2.Columns(4), 0)
        If Not IsError(m) Then
            'match row, compare values
            For Each cTest In Application.Intersect(c.EntireRow, ws1.UsedRange).Cells
                Set cMatch = ws2.Cells(m, cTest.Column)
                If cTest.Value <> cMatch.Value Then
                    cMatch.Interior.Color = vbGreen
                End If
            Next cTest
        Else
            'no match found
            c.EntireRow.Interior.Color = vbRed
            Debug.Print "No match for '" & c.Value & "' (Row " & c.Row & ")"
        End If
    Next c

'do a loop for worksheet 2
    For Each c In ws2.Range(ws2.Range("D2"), ws2.Cells(ws2.Rows.Count, "D").End(xlUp)).Cells
        m = Application.Match(c.Value, ws1.Columns(4), 0)
        If Not IsError(m) Then
            'match row, compare values
            For Each cTest In Application.Intersect(c.EntireRow, ws2.UsedRange).Cells
                Set cMatch = ws1.Cells(m, cTest.Column)
                If cTest.Value <> cMatch.Value Then
                    cMatch.Interior.Color = vbGreen
                End If
            Next cTest
        Else
            'no match
            c.EntireRow.Interior.Color = vbRed
            Debug.Print "No match for '" & c.Value & "' (Row " & c.Row & ")"
        End If
    Next c

End Sub

Private Sub CommandButton2_Click()
'reset format button
ThisWorkbook.Sheets(1).Cells.ClearFormats
ThisWorkbook.Sheets(2).Cells.ClearFormats

End Sub