【问题标题】:Excel vLookup Returning 0Excel vLookup 返回 0
【发布时间】:2015-05-12 22:48:18
【问题描述】:

我正在处理两个非常大的表,我正在尝试使用 vba 和 vlookups 来匹配一个与另一个中的数据。

每个工作表都是一列,结构如下:

参考表:
ID_Ref (2/4)
Q1234
W1234
R1234
...

查找表
ID_Lookup
Q1234
P1234
X1234
...

我有兴趣识别 Lookup SSheet 中但不在 Reference Sheet 中的行。我在每张表中有大量行(查找中约 130k,参考中约 90k),当我尝试手动输入公式时,excel 不断崩溃。

因此,我尝试使用 VBA 来自动化该过程。问题是下面的函数对大多数行返回 0,我不知道为什么。

    Sub Vlookup()

    With Sheets("Lookup).Range("B3:B133780")
        .FormulaR1C1 = _
        "=IF(VLOOKUP(RC[-1],2_4!R1C1:R79145C1,1)=RC[-1],VLOOKUP(RC[-1],2_4!R1C1:R79145C2,1,FALSE),VLOOKUP(RC[-1],2_4!R1C1:R79145C2,1,FALSE))"
        .Value = .Value
    End With 
    End Sub

感谢任何帮助!

编辑 5/13:

我尝试了@HarveyFrench 和@Jeeped 提到的方法,得到了两个不同的结果。

复制下来:

=NOT(ISNA(VLOOKUP($A2,'2_4'!$A$1:$A$79145,1, FALSE)))

产生与复制不同数量的不匹配记录

=IFERROR(MATCH(A2,'2_4'!$A$1:$A$79145,0),"")

我在这里做错了吗?

【问题讨论】:

  • 如果只是为了识别存在我会尽快使用 countif 而不是 cpu 密集型 VLookup。如果 countif 返回零,您就知道它不存在,任何高于零的都存在
  • 根据数据的类型,您可以使用Data->Remove Duplicates 来减小它的大小。如果您只是测试两个列表中的项目,这将有效。您还可以调用函数Application.Match 的VBA 版本并在VBA 中处理结果,而无需将公式放入工作表中。 Application.Match 在这里是理想的,因为您只是想测试存在。
  • MATCH functionIFERROR function 将返回一个零长度字符串,虽然它不是真正的空白,但可以用COUNTBLANK function 计算。如果您想用 VLOOKUP 的 #N/A 计算 #N/A,请删除 IFERROR 包装器。

标签: vba excel vlookup


【解决方案1】:

如果您只想证明存在,MATCH functionVLOOKUP function 甚至 COUNTIF function 更有效。

With Sheets("Lookup).Range("B3:B133780")
    .Formula = "=iferror(match(a3, '2_4'!A:A, 0), """")"
    .cells = .value2
End With 

在 B 列的工作表“2_4”上,您将留下空白单元格和包含匹配行号的单元格。

【讨论】:

  • 虽然匹配更好,但您的示例不起作用,因为单元格 a3 是在文本字符串中硬编码的......我不会费心使用 VBA 来设置公式,我会使用match 比 vlookup 做的少,而且会更快一些。 vlookup 值得学习,因为它非常方便。
  • @HarveyFrench - 保持 A3 相对并一次填充一列单元格与向下填充具有相同的效果;例如A3 将按行调整。
  • 很高兴我不是唯一一个在这个问题上质疑你的人 Jeeped :)。
  • 哦哦。我不知道。一个很好的提示,尽管我怀疑去掉“.cells = .value2”这一行并保留公式将是 RosenkranzC 可能会使用它的方式。
  • 经过一番摆弄,这是处理时间最少的解决方案。谢谢大家的帮助!
【解决方案2】:

这是yoru公式,看起来很狡猾!

'=IF(VLOOKUP(RC[-1],2_4!R1C1:R79145C1,1)=RC[-1]
    ,VLOOKUP(RC[-1],2_4!R1C1:R79145C2,1,FALSE)
    ,VLOOKUP(RC[-1],2_4!R1C1:R79145C2,1,FALSE))

在具有值的查找列右侧的列中的单元格中(我假设它是 A 列并从第 2 行开始。在单元格 B2 中尝试此公式,然后将其复制并粘贴下来:

=NOT(  ISNA(   VLOOKUP($A2,'2_4'!$A$1:$A$79145,1, FALSE)   )   )

当找到值时返回 true,否则返回 false。

我认为您需要重新阅读 VLOOKUP 的手册页,因为您没有正确使用它。

您可能希望在编辑时使用功能区>>公式选项卡>>计算选项来关闭自动计算,但我认为没有必要。

哈维

【讨论】:

  • 关于查看 Harvey 的 vlookup 的好点,@RosenkranzC 你的公式实际上是说如果 vlookup 的结果是左侧的单元格,则返回 vlookup 的结果...... . 否则也返回 vlookup 的结果,虽然它会给你一些你想要的东西(最终是一个不存在的 #N/A)你正在运行 vlookup 进行测试,然后不管结果如何,只是没有 if 的 vlookup 本身是相同的结果,计算更少。
【解决方案3】:

这是使用 ADO 的另一种方法(改编自 this answer,但已修改为使用 Excel 2007 及更高版本的连接字符串并仅标识查找表唯一的项目。)我假设查找表被调用“查找”,参考表称为“参考”,我们识别的项目列表将输出到名为“数据”的表 - 如果这些名称错误,请替换为正确的名称。

在 VBA 编辑器中,转到工具 > 参考并添加对“Microsoft ActiveX 数据对象 2.8 库”的引用。现在将其添加到标准代码模块中,然后运行它:

Option Explicit

Sub get_employees()

Dim cn As ADODB.Connection
Set cn = New ADODB.Connection

' Connection string for .xlsm files
With cn
    .Provider = "Microsoft.ACE.OLEDB.12.0"
    .ConnectionString = "Data Source=" & ThisWorkbook.FullName & ";" & _
        "Extended Properties=""Excel 12.0 Macro;IMEX=1;HDR=Yes"";"
    .Open
End With

Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset

rs.Open "SELECT [Lookup$].[ID_Lookup] FROM [Lookup$] LEFT JOIN [Reference$] ON [Lookup$].[ID_Lookup] = " & _
    "[Reference$].[ID_Ref] WHERE [Reference$].[ID_Ref] IS NULL", cn

With Worksheets("Data")
    .Cells(2, 1).CopyFromRecordset rs
End With

rs.Close
cn.Close

End Sub

这会尝试将查找表中的每个条目与参考表中的一个或多个对应条目进行匹配。然后它会消除所有匹配项,只保留不匹配的查找条目。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-19
    • 2020-12-16
    • 1970-01-01
    • 2019-05-02
    相关资源
    最近更新 更多