Excel精英培训网

 找回密码
 注册
数据透视表40+个常用小技巧,让你一次学会!
查看: 2996|回复: 8

[已解决]高效多条件匹配带有重复记录的数据

[复制链接]
发表于 2014-9-17 08:04 | 显示全部楼层 |阅读模式
本帖最后由 glhfgtd 于 2014-9-17 15:24 编辑

工作上需要我在AP表中找出相匹配的EP表的内容。由于数据量的庞大(3万多行),我用的函数公式引用单元格逐个匹配的方法耗时费力,有时甚至导致Excel无反应重启。所以求教这里的VBA能手帮忙编写一个通过VBA数组在内存中计算匹配的代码程序来解决这个问题。(当然,若有更快速效率的方法,求之不得!!!)
匹配规则:
1)根据APABC列的字符串和E列的金额在EP表中进行查询匹配,若在 EPB列中查找到同时含有APABC列的字符串并且EPD列金额等于APE列的金额,(请注意: 因为记录中含有重复数据,所以匹配不是一一对应关系)那么请在AP表的G列返回EPA列相对应的Key(重复数据要是第一次匹配到,则返回第一个匹配到的AKey值,若是第二次匹配到,则返回第二个匹配到的AKey已匹配过的记录不能再次进行匹配,要是我这里解释的不明白请参见我在API2J2使用的函数公式)
2)若规则(1)没有匹配到任何记录,接下来根据APD列的号码和E列的金额在EP表中进行查询匹配。若在EPC列和D列同时匹配到APD列、E列的内容,那么请在AP表的G列返回相应的EPA列的Key (同样,已匹配过的记录不能再次进行匹配)
3)若以上规则(1)(2)均没能找到其匹配对应项,则在AP表的G列返回空值
谢谢

EP_AP Matching.zip (301.04 KB, 下载次数: 21)
excel精英培训的微信平台,每天都会发送excel学习教程和资料。扫一扫明天就可以收到新教程
发表于 2014-9-17 11:09 | 显示全部楼层    本楼为最佳答案   
先来个双循环的
  1. Sub 匹配()
  2.     arr = Sheets("ep").[a1].CurrentRegion
  3.     brr = Sheets("ap").Range("a1:g" & Sheets("ap").[a65536].End(3).Row)
  4.     n = UBound(arr)
  5.     For i = 2 To UBound(brr)
  6.         str1 = brr(i, 1): str2 = brr(i, 2): str3 = brr(i, 3)
  7.         am = brr(i, 5)   'amount
  8.         For j = 2 To n
  9.             x = arr(j, 2): xam = arr(j, 4)
  10.             If am = xam Then
  11.                 If InStr(x, str1) > 0 And InStr(x, str2) > 0 And InStr(x, str3) > 0 Then       '规则1,判断同时含有ABC列字符串
  12.                     brr(i, 7) = arr(j, 1)
  13.                     For k = 1 To UBound(arr, 2): arr(j, k) = arr(n, k): Next     '把最后一行移到当前行
  14.                     n = n - 1         '最后一行减1
  15.                     GoTo aa
  16.                 End If
  17.                
  18.                 If brr(i, 4) = arr(j, 3) Then        '规则2,判断serial
  19.                     brr(i, 7) = arr(j, 1)
  20.                     For k = 1 To UBound(arr, 2): arr(j, k) = arr(n, k): Next        '把最后一行移到当前行
  21.                     n = n - 1       '最后一行减1
  22.                     GoTo aa
  23.                 End If
  24.             End If
  25.         Next
  26. aa:
  27.     Next
  28.     Sheets("ap").[g1].Resize(UBound(brr), 1) = Application.Index(brr, , 7)
  29. End Sub
复制代码

点评

谢谢您帮忙解答,完全满足我的需求。而且代码的速度很快,向您致敬学习!  发表于 2014-9-17 11:34

评分

参与人数 1 +12 收起 理由
glhfgtd + 12 赞一个!

查看全部评分

回复

使用道具 举报

发表于 2014-9-17 11:11 | 显示全部楼层
请看附件。

EP_AP Matching.rar

200.53 KB, 下载次数: 38

回复

使用道具 举报

发表于 2014-9-17 14:28 | 显示全部楼层
来个字典的。。。。。。。。
  1. Sub 匹配1()
  2.     arr = Sheets("ep").[a1].CurrentRegion
  3.     Set d = CreateObject("scripting.dictionary")
  4.     brr = Sheets("ap").Range("a1:g" & Sheets("ap").[a65536].End(3).Row)
  5.     For i = 2 To UBound(arr)
  6.         am = arr(i, 4)
  7.         d(am) = d(am) & "," & i            '把指定amount的行数存入字典
  8.     Next
  9.     For i = 2 To UBound(brr)
  10.         am = brr(i, 5)   'amount
  11.         If d.exists(am) Then         '对于指定amount
  12.             xrr = Split(d(am), ",")        '所有行数
  13.             If UBound(xrr) >= 1 Then
  14.                 str1 = brr(i, 1): str2 = brr(i, 2): str3 = brr(i, 3)
  15.                 For k = 1 To UBound(xrr)
  16.                     j = Val(xrr(k))       '行数
  17.                     If j > 0 Then
  18.                         x = arr(j, 2)
  19.                         If InStr(x, str1) > 0 And InStr(x, str2) > 0 And InStr(x, str3) > 0 Then       '规则1,判断同时含有ABC列字符串
  20.                             brr(i, 7) = arr(j, 1)
  21.                             d(am) = Replace(d(am) & ",", "," & j & ",", ",")        '去掉已判断过的
  22.                             GoTo aa
  23.                         End If
  24.                     End If
  25.                 Next
  26.                
  27.                 For k = 1 To UBound(xrr)
  28.                     j = Val(xrr(k))
  29.                     If j > 0 Then
  30.                         x = arr(j, 2)
  31.                         If brr(i, 4) = arr(j, 3) Then        '规则2,判断serial
  32.                             brr(i, 7) = arr(j, 1)
  33.                             d(am) = Replace(d(am) & ",", "," & j & ",", ",")
  34.                             GoTo aa
  35.                         End If
  36.                     End If
  37.                 Next
  38.             End If
  39.         End If
  40. aa:
  41.     Next
  42.     Sheets("ap").[g1].Resize(UBound(brr), 1) = Application.Index(brr, , 7)
  43. End Sub
复制代码

评分

参与人数 1 +12 收起 理由
glhfgtd + 12 赞一个!

查看全部评分

回复

使用道具 举报

发表于 2014-9-17 14:29 | 显示全部楼层
我觉得2楼的代码可能有点问题,某些情况下会把规则2先于规则1的记录给筛选出来。
回复

使用道具 举报

发表于 2014-9-17 14:31 | 显示全部楼层
对比着用一下吧,如果数据量大的话,估计代码2要快一些。

EP_AP Matching.rar

202.35 KB, 下载次数: 44

回复

使用道具 举报

 楼主| 发表于 2014-9-17 14:48 | 显示全部楼层
本帖最后由 glhfgtd 于 2014-9-17 15:23 编辑
grf1973 发表于 2014-9-17 14:31
对比着用一下吧,如果数据量大的话,估计代码2要快一些。

谢谢您的解答,在实际应用中发现导入了更多的数据后,有的数据文本有英文大小写差异,我把If InStr(x, str1) > 0 改为If InStr(x, str1,1) > 0 进行文本比较,因有的str1为空,得到"类型不匹配"错误,麻烦您帮忙修改一下代码使其能够进行文本比较(忽视大小写的不同)
回复

使用道具 举报

发表于 2014-9-17 16:07 | 显示全部楼层
把要对比的全部转换成大写或小写就行了:
str1 = UCase(brr(i, 1)): str2 = UCase(brr(i, 2)): str3 = UCase(brr(i, 3))
......
x = UCase(arr(j, 2))
.....

评分

参与人数 1 +12 收起 理由
glhfgtd + 12 很给力!

查看全部评分

回复

使用道具 举报

 楼主| 发表于 2014-9-17 16:17 | 显示全部楼层
grf1973 发表于 2014-9-17 16:07
把要对比的全部转换成大写或小写就行了:
str1 = UCase(brr(i, 1)): str2 = UCase(brr(i, 2)): str3 = UCa ...

谢谢指点,有学了一招。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|Excel精英培训 ( 豫ICP备11015029号 )

GMT+8, 2024-4-26 07:24 , Processed in 0.417344 second(s), 16 queries , Gzip On, Yac On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表