Excel VBA - 检查一个范围内每个单元格的值是否在另一个范围内

时间:2016-08-08 14:25:23

标签: vba excel-vba excel

我正在尝试使用新票证数据更新当前工作票据数据的工作簿。我已经为底部的每个循环嵌套,以检查票号中是否相等。如果找到匹配,则应该使用新数据更新某些单元格。如果该票证不在我的票证列表中,则应该将新票证添加到底部。不断发生的事情是,即使对于电子表格中的票证,它也会不断地将所有票据从newData添加到currentData的底部。我认为问题最终取决于这些嵌套for循环中的逻辑,但我无法弄清楚我做错了什么。

Sub getNewData()

Dim newData As Workbook
Dim ndLastRow As Long
Dim currentData As Workbook
Dim cdLastRow As Long
Dim ndRangeToCheck As Range
Dim cdRangeToCheck As Range
Dim ndRow As Long
Dim cdRow As Long

Set newData = Workbooks.Open("C:\Users\<user>\Documents\newData.xlsx")
Set currentData = ThisWorkbook

' Assign last row and the range to compare for each workbook
newData.Worksheets("Incident List").Range("A2").Select
With ActiveSheet
    ndLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Set ndRangeToCheck = newData.Worksheets("Incident List").Range("A2", Cells(ndLastRow, "A"))

currentData.Worksheets("Incident List").Activate
With ActiveSheet
    cdLastRow = .Cells(.Rows.Count, "B").End(xlUp).Row
End With
Set cdRangeToCheck = currentData.Worksheets("Incident List").Range("B2", Cells(cdLastRow, "B"))

' Iterate through to compare Incident #s between workbooks
Dim rout As Range
Dim rin As Range
Dim match As Boolean
For Each rout In ndRangeToCheck.Cells
    match = False
    For Each rin In cdRangeToCheck.Cells
        If Cells(rin.Row, rin.Column).Value = Cells(rout.Row, rout.Column).Value Then
            match = True
            ndRow = rout.Row
            cdRow = rin.Row
            currentData.Worksheets("Incident List").Cells(cdRow, "L").Value = newData.Worksheets("Incident List").Cells(ndRow, "D").Value
            currentData.Worksheets("Incident List").Cells(cdRow, "O").Value = newData.Worksheets("Incident List").Cells(ndRow, "F").Value
            currentData.Worksheets("Incident List").Cells(cdRow, "P").Value = newData.Worksheets("Incident List").Cells(ndRow, "G").Value
            currentData.Worksheets("Incident List").Cells(cdRow, "Q").Value = newData.Worksheets("Incident List").Cells(ndRow, "H").Value
            currentData.Worksheets("Incident List").Cells(cdRow, "S").Value = newData.Worksheets("Incident List").Cells(ndRow, "L").Value
            currentData.Worksheets("Incident List").Cells(cdRow, "T").Value = newData.Worksheets("Incident List").Cells(ndRow, "N").Value
            currentData.Worksheets("Incident List").Rows(rin.Row).Borders.LineStyle = xlContinuous

            Exit For
        End If
    Next rin

    If match = False Then
        ndRow = rout.Row
        currentData.Worksheets("Incident List").Cells(cdLastRow, "B").Offset(1, 0).Value = newData.Worksheets("Incident List").Cells(ndRow, "A").Value
        currentData.Worksheets("Incident List").Cells(cdLastRow, "B").Offset(1, 0).NumberFormat = "0"
        currentData.Worksheets("Incident List").Cells(cdLastRow, "L").Offset(1, 0).Value = newData.Worksheets("Incident List").Cells(ndRow, "D").Value
        currentData.Worksheets("Incident List").Cells(cdLastRow, "O").Offset(1, 0).Value = newData.Worksheets("Incident List").Cells(ndRow, "F").Value
        currentData.Worksheets("Incident List").Cells(cdLastRow, "P").Offset(1, 0).Value = newData.Worksheets("Incident List").Cells(ndRow, "G").Value
        currentData.Worksheets("Incident List").Cells(cdLastRow, "Q").Offset(1, 0).Value = newData.Worksheets("Incident List").Cells(ndRow, "H").Value
        currentData.Worksheets("Incident List").Cells(cdLastRow, "S").Offset(1, 0).Value = newData.Worksheets("Incident List").Cells(ndRow, "L").Value
        currentData.Worksheets("Incident List").Cells(cdLastRow, "T").Offset(1, 0).Value = newData.Worksheets("Incident List").Cells(ndRow, "N").Value
        currentData.Worksheets("Incident List").Cells(cdLastRow, "F").Offset(1, 0).Value = newData.Worksheets("Incident List").Cells(ndRow, "C").Value
        currentData.Worksheets("Incident List").Cells(cdLastRow, "M").Offset(1, 0).Value = newData.Worksheets("Incident List").Cells(ndRow, "E").Value
        currentData.Worksheets("Incident List").Cells(cdLastRow, "M").Offset(1, 0).NumberFormat = "m/d/yyyy"
        currentData.Worksheets("Incident List").Rows(cdLastRow).Offset(1, 0).Borders.LineStyle = xlContinuous

        ' Reset cdLastRow
        currentData.Worksheets("Incident List").Activate
        With ActiveSheet
            cdLastRow = .Cells(.Rows.Count, "B").End(xlUp).Row
        End With
    End If
Next rout

newData.Close
End Sub

1 个答案:

答案 0 :(得分:0)

我认为错误在以下几行:

If Cells(rin.Row, rin.Column).Value = Cells(rout.Row, rout.Column).Value

其中两个Cells引用都指向currentData,而我认为这对于第一个Cells出现是正确的,而第二个应该指向newData

这是因为使用了Select / Selection和/或Activate / ActiveYYY方法/对象,这些方法/对象容易对实际引用的工作簿/工作表进行松散控制

您应该使用完全限定范围引用,直到其父工作簿

除此之外,你可以利用Find()方法来避免循环和...一些小技巧来缩短代码,如下所示:

Option Explicit

Sub getNewData()
    Dim newData As Worksheet, currentData As Worksheet '<--| use just the worksheets since they are what you actually need to work with
    Dim ndRangeToCheck As Range, cdRangeToCheck As Range '<-- data ranges
    Dim rout As Range, f As Range '<--| helper ranges
    Dim cdRow As Long
    Dim cdAddressStrng As String, ndAddressStrng As String

    Workbooks.Open "C:\Users\<user>\Documents\newData.xlsx"
    Set newData = ActiveWorkbook.Worksheets("Incident List") '<--| set just the sheet since it is what you actually need to work with
    Set currentData = ThisWorkbook.Worksheets("Incident List") '<--| set just the sheet since it is what you actually need to work with

    ' Assign last row and the range to compare for each workbook
    With newData
        Set ndRangeToCheck = .Range("A2", .Cells(.Rows.Count, "A").End(xlUp))
    End With

    With currentData
        Set cdRangeToCheck = .Range("B2", .Cells(.Rows.Count, "B").End(xlUp))
    End With

    cdAddressStrng = "L|, O|, P|, Q|, S|, T|"
    ndAddressStrng = "D|, F|, G|, H|, L|, N|"

    ' Iterate through to compare Incident #s between workbooks
    For Each rout In ndRangeToCheck
        Set f = cdRangeToCheck.Find(What:=rout.value, lookat:=xlWhole, LookIn:=xlValues, MatchCase:=False) '<--| look for the "new" value into current data
        If f Is Nothing Then '<--| if not found...
            cdRow = currentData.Cells(currentData.Rows.Count, "B").End(xlUp).row + 1 '<--| ...retrieve current data first empty row
        Else '<--| otherwise...
            cdRow = f.row '<--| ......retrieve found cell row index
        End If
        currentData.Range(Replace(cdAddressStrng, "|", cdRow)).value = newData.Range(Replace(ndAddressStrng, "|", rout.row)).value
        currentData.Rows(cdRow).Borders.LineStyle = xlContinuous
    Next rout

    newData.Parent.Close '<--| close newdata workbook: since newData is a worksheet we need to "climb up" to its parent workbook
End Sub