【问题标题】:compare two sheets values in excel比较excel中的两个工作表值
【发布时间】:2019-12-05 03:00:27
【问题描述】:

如何将 sheet-1 的一列的所有值与具有不同 sheet-2 的另一列值进行比较,如果匹配,则将 sheet-1 的一列对应的值返回到 excel 中 sheet-2 的另一列?

【问题讨论】:

  • 您希望将第 1 列中的每个值与第 2 列中的每个值进行比较(列的位置没有区别)。如果找到匹配项,不清楚你想做什么

标签: vba excel


【解决方案1】:

假设您的值位于名为 Sheet1Sheet2 的工作表的 A 列中。然后,您可以将以下公式放入Sheet2B1 并向下拖动以覆盖您想要的范围:=IF(Sheet1!A1=Sheet2!A1,Sheet2!A1,"")

或者,如果您更喜欢使用 VBA,请将此代码放入模块中:

Sub columnCompare()
Dim sh1 As Worksheet, sh2 As Worksheet, r1 As Range, r2 As Range
  Set sh1 = Worksheets("Sheet1")
  Set sh2 = Worksheets("Sheet2")
  Set r1 = sh1.Range("A1")
  Set r2 = sh2.Range("A1")
  While r1 <> "" And r2 <> ""
    If r1 = r2 Then r2.Offset(0, 1) = r1
    Set r1 = r1.Offset(1, 0)
    Set r2 = r2.Offset(1, 0)
  Wend
End Sub

【讨论】:

    【解决方案2】:

    如果我理解正确,这就是你想要的,

    Sheet1

    Sheet2

    sheet2B2中输入以下公式,如图所示向下拖动,

    =INDEX(Sheet1!B:B,MATCH(A2,Sheet1!A:A,0),1)
    

    【讨论】:

      【解决方案3】:

      我只能回答您的部分问题:比较两列并检测它们是否不同

      您在上面的Tony M 的回答中有一个很好的教程答案。

      但是,这将在大型数据集上执行得很慢,因为:

      1. 一次读取一个单元格的范围非常慢;
      2. 逐对比较值效率低下,尤其是对于字符串,当值的数量达到数万时,
      Point(1) 是重要的一点:VBA 使用var = Range("A1") 拾取单个单元格所花费的时间与使用var = Range("A1:Z1024") 一次性拾取整个范围所花费的时间相同;与工作表的每次交互所花费的时间是 VBA 中字符串比较的四倍,是浮点小数比较的二十倍;反过来,这比整数比较长三倍。

      因此,如果您一次读取整个范围,并在 VBA 中处理 Range.Value2 数组,您的代码可能快四倍,甚至可能快一百倍。

      这是在 Office 2010 和 2013 中(我测试过它们);对于旧版本的 Excel,对于与单元格或范围细胞。这将*慢**慢,因为在新旧版本的 Excel 中,VBA 操作仍将是个位数的微秒数:您的代码将运行至少快一百倍,甚至可能数千倍如果您避免在旧版本的 Excel 中逐个单元格地读取工作表,则速度会更快。

      在一次“点击”中拾取范围,然后在 VBA 中对数组的每个项目进行比较,这样可以获得很大的收益 - 用户可感知的间隔。

      
      arr1  = Range1.Values
      arr2  = Range2.Values
      ' Consider checking that the two ranges are the same size
      For i = LBound(arr1, 1) To Ubound(arr1, 2)
      For j = LBound(arr1, 2) To Ubound(arr1, 2)
      If arr1(i, j) <> arr2(i, j) Then bMatchFail = True Exit For End If
      Next j
      If bMatchFail Then Exit For
      Next i
      Erase arr1 Erase arr2

      您会注意到此代码示例是通用的,适用于从任何地方获取的两个相同大小的范围 - 甚至来自不同的工作簿。如果您要比较两个相邻的列,则加载一个包含两列的数组并比较 IF arrX(i, 1) &lt;&gt; arrX(i,2) Then 将使运行时间减半。

      仅当您从大范围中提取数万个值时,您的下一个挑战才有意义:对于小于此范围的任何值,此扩展答案都没有性能提升。

      我们正在做的是:

      使用哈希函数比较两个大范围的值

      这个想法非常简单,尽管基础数学对非数学家来说相当具有挑战性:我们不是一次比较一个值,而是运行一个数学函数,将这些值“散列”成一个简短的标识符,以便于比较。

      如果您将范围与“参考”副本进行比较,则可以存储“参考”哈希,这样可以将工作量减半。

      目前有一些快速可靠的散列函数,它们在 Windows 中作为安全和加密 API 的一部分提供。有一个小问题是它们在字符串上运行,我们有一个数组要处理;但是您可以轻松找到一个快速的“Join2D”函数,该函数从范围的.Value2 属性返回的二维数组中获取字符串。

      因此,两个大范围的快速比较函数将如下所示:

      Public Function RangeCompare(Range1 as Excel.Range, Range2 As Excel.Range) AS Boolean
      ' Returns TRUE if the ranges are identical.
      ' This function is case-sensitive.
      ' For ranges with fewer than ~1000 cells, cell-by-cell comparison is faster
      ' WARNING: This function will fail if your range contains error values.
      RangeCompare = False
      If Range1.Cells.Count &LT;&GT; Range2.Cells.Count Then RangeCompare = False ElseIf Range1.Cells.Count = 1 then RangeCompare = Range1.Value2 = Range2.Value2 Else RangeCompare = MD5(Join2D(Range1.Value2)) = MD5(Join2D(Range2.Value2)) Endif
      End Function

      我在这个 VBA 函数中封装了 Windows System.Security MD5 哈希:

      Public Function MD5(arrBytes() As Byte) As String
      ' Return an MD5 hash for any string
      ' Author: Nigel Heffernan Excellerando.Blogspot.com
      ' Note the type pun: you can pass in a string, there's no type conversion or cast ' because a string is stored as a Byte array and VBA recognises this.
      Dim oMD5 As Object 'Set a reference to mscorlib 4.0 to use early binding

      Dim HashBytes() As Byte Dim i As Integer

      Set oMD5 = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider") HashBytes = oMD5.ComputeHash_2((arrBytes))
      For i = LBound(HashBytes) To UBound(HashBytes) MD5 = MD5 & Right("00" & Hex(HashBytes(i)), 2) Next i

      Set oMD5 = Nothing ' if you're doing this repeatedly, declare at module level and persist Erase HashBytes

      End Function
      还有其他的 VBA 实现,但似乎没有人知道字节数组/字符串类型双关语 - 它们不是 等效,它们是 相同 - 所以每个人都不需要编写代码类型转换。

      一个快速简单的 Join2D 函数是 2015 年的posted by Dick Kusleika on Daily Dose of Excel

      Public Function Join2D(ByVal vArray As Variant, Optional ByVal sWordDelim As String = " ", Optional ByVal sLineDelim As String = vbNewLine) As String
      
          Dim i As Long, j As Long
          Dim aReturn() As String
          Dim aLine() As String
      
          ReDim aReturn(LBound(vArray, 1) To UBound(vArray, 1))
          ReDim aLine(LBound(vArray, 2) To UBound(vArray, 2))
      
          For i = LBound(vArray, 1) To UBound(vArray, 1)
              For j = LBound(vArray, 2) To UBound(vArray, 2)
                  'Put the current line into a 1d array
                  aLine(j) = vArray(i, j)
              Next j
              'Join the current line into a 1d array
              aReturn(i) = Join(aLine, sWordDelim)
          Next i
      
          Join2D = Join(aReturn, sLineDelim)
      
      End Function
      

      如果您需要在进行比较之前删除空白行,则需要Join2D function I posted in StackOverflow back in 2012

      这种类型的哈希比较最常见的应用是电子表格控制 - 更改监控 - 您会看到使用 Range1.Formula 而不是 Range1.Value2:但您的问题是关于比较值,而不是公式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多