ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 2282|回复: 6

[原创] 多基本资料建立字典的通用字典建立范例

[复制链接]

TA的精华主题

TA的得分主题

发表于 2019-11-2 10:57 | 显示全部楼层 |阅读模式
今天看了求助贴http://club.excelhome.net/thread-1506094-1-1.html
针对多个基本资料需要建立字典,使用通用代码建立,以减少编程写码繁复
特此编写一个范例,以供大家参考使用。如有不足之处,敬请指出。
附上附件以供参考
多基本资料建立字典的通用建立范例(by.micro).rar (75.23 KB, 下载次数: 157)
建立模块,抄写代码
  1. Public dicBSC As Object, dicZGS As Object
  2. Private vData As Variant, nRow As Double, nCol As Double

  3. Sub WorkSheetChange(ByVal Target As Range)
  4.     Dim vFill As Variant, rArea As Range, rIntersect As Range
  5.     Dim vIntersect As Variant, vDataCol As Variant, vFillCol As Variant, nI As Long
  6.    
  7.     If dicBSC Is Nothing Or dicZGS Is Nothing Then 建立基本资料
  8.     vFill = Split(",6,35", ",") '办事处标识、子公司的列数
  9.     ReDim vDataCol(1 To UBound(vFill))
  10.     For nI = 1 To UBound(vDataCol)
  11.         vDataCol(nI) = Val(vFill(nI)) '转化为需要处理的列数
  12.     Next
  13.     vFill = Split(",54,57", ",") '对应填写列数
  14.     ReDim vFillCol(1 To UBound(vFill))
  15.     For nI = 1 To UBound(vFillCol)
  16.         vFillCol(nI) = Val(vFill(nI)) '转化为需要填写的列数
  17.     Next
  18.    
  19.     vData = Target.Parent.UsedRange.Value '获取引起变动的表的已用单元格的数据
  20.     If UBound(vData) < 7 Then Exit Sub '当小于7行,即只有标题行
  21.     Application.EnableEvents = False '屏蔽系统响应
  22.     For Each rArea In Target.Areas '检查引起变化的每个单元格区域(因为可能通过Ctrl选择而导致引起多个单元格区域)
  23.         For nI = 1 To UBound(vDataCol) '检查每个需要处理的列
  24.             Set rIntersect = Intersect(rArea, Cells(7, vDataCol(nI)).Resize(UBound(vData) - 6)) '单元格区域与需要处理的列的交集
  25.             If Not rIntersect Is Nothing Then '单元格区域与需要处理的列发生交集
  26.                 With rIntersect
  27.                     If .Rows.Count = 1 Then '如果交集只有一行,直接获取对应数值时,得到不是数组
  28.                         ReDim vIntersect(1 To 1, 1 To 1) '强制使用数组方式,以便后面代码使用
  29.                         vIntersect(1, 1) = .Value
  30.                     Else
  31.                         vIntersect = .Value '交集的数值转换成数组
  32.                     End If
  33.                     ReDim vFill(.Row To .Row + .Rows.Count - 1, 1 To 1) '建立需要填写结果的数组
  34.                     For nRow = LBound(vFill) To UBound(vFill)
  35.                         If vDataCol(nI) = 6 Then '办事处标识
  36.                             If dicBSC.Exists("|" & vData(nRow, 5) & "|" & vData(nRow, 6)) Then '办事处字典中存在“|省份|城市”
  37.                                 vFill(nRow, 1) = dicBSC("|" & vData(nRow, 5) & "|" & vData(nRow, 6))
  38.                             End If
  39.                         ElseIf vDataCol(nI) = 35 Then '子公司
  40.                             If dicZGS.Exists("|" & vData(nRow, 35)) Then '子公司字典中存在“|省份”
  41.                                 If dicZGS("|" & vData(nRow, 35)).Exists(vData(nRow, 5)) Then '“|省份”子公司字典中存在“|城市”
  42.                                      vFill(nRow, 1) = dicZGS("|" & vData(nRow, 35))("|" & vData(nRow, 5))
  43.                                 End If
  44.                             End If
  45.                         End If
  46.                     Next
  47.                     Cells(LBound(vFill), vFillCol(nI)).Resize(UBound(vFill) - LBound(vFill) + 1) = vFill '在需要填写的列上填上数组
  48.                 End With
  49.             End If
  50.         Next
  51.     Next
  52.     Application.EnableEvents = True
  53. End Sub

  54. Private Sub 建立基本资料()
  55.     vData = Sheet3.UsedRange.Value
  56.     Set dicBSC = CreateDic(StartRow:=2, UnitKeyCol:="13,14", UnitItemCol:=15) '所属办事处
  57.     Set dicZGS = CreateDic(StartRow:=2, UnitKeyCol:=24, TitleCol:="25,26") '子公司
  58. End Sub

  59. Private Function CreateDic(ByVal StartRow As Long, ByVal UnitKeyCol As String, Optional ByVal UnitItemCol As String, Optional ByVal TitleCol As String) As Object
  60. '功能:根据(多列)关键字列、指定(多列)Item列、指定(多列)标题列,建立字典
  61. '注意:关键字将用“|Key1|Key2……"形式建立;如果多列Item,将建立为数组;iTem列与标题列不能同时存在,否则优先选用Item列作为建立字典依据
  62. 'UnitKeyCol,多列关键字时用逗号区分
  63. 'UnitItemCol,多列Item时用逗号区分
  64. 'TitleCol,多列标题时用逗号区分
  65. 'StartRow,数据源起始读取数据行
  66.     Dim oDic As Object
  67.     Dim vKeyCol As Variant, nKeyCol As Double, vItemCol As Variant, nItemCol As Double, vTitleCol As Variant, nTitleCol As Double
  68.     Dim nI As Integer, sKey As String, vItem As Variant, vTitle As Variant
  69.     Dim vTmp As Variant, bItemFirst As Boolean
  70.    
  71.     If UnitKeyCol = "" Then Exit Function '没有关键字列数据
  72.     vTmp = Split(UnitKeyCol, ",") '将关键字列数据转换成数组
  73.     ReDim vKeyCol(UBound(vTmp)) '定义关键字列数组
  74.     For nI = LBound(vTmp) To UBound(vTmp)
  75.         If Int(Val(vTmp(nI))) < 1 Then Exit Function '如果关键字列数被误填为非整数时退出字典建立
  76.         vKeyCol(nI) = Int(Val(vTmp(nI)))  '将关键字列数据数组转换成数字
  77.     Next
  78.    
  79.     If UnitItemCol <> "" Then 'Item列数据非空
  80.         vTmp = Split(UnitItemCol, ",") '将Item列数据转换成数组
  81.         ReDim vItemCol(UBound(vTmp)) '定义Item列数组
  82.         For nI = LBound(vTmp) To UBound(vTmp)
  83.             If Int(Val(vTmp(nI))) < 1 Then Exit Function '如果Item列数被误填为非整数时退出字典建立
  84.             vItemCol(nI) = Int(Val(vTmp(nI))) '将Item列数据数组转换成数字
  85.         Next
  86.         If UBound(vItemCol) > 0 Then '非单个Item
  87.             ReDim vItem(1 To UBound(vItemCol) + 1) '定义Item数组
  88.         Else
  89.             vItemCol = vItemCol(0)
  90.         End If
  91.         bItemFirst = True '优先直接使用Item列数据
  92.     ElseIf TitleCol <> "" Then '标题列数据非空
  93.         vTmp = Split(TitleCol, ",") '将标题列数据转换成数组
  94.         ReDim vTitleCol(UBound(vTmp)) '定义标题列数组
  95.         ReDim vTitle(UBound(vTitleCol)) '定义标题数组
  96.         For nI = LBound(vTmp) To UBound(vTmp)
  97.             If Int(Val(vTmp(nI))) < 1 Then Exit Function '如果标题列数被误填为非整数时退出字典建立
  98.             vTitleCol(nI) = Int(Val(vTmp(nI))) '将标题列数据数组转换成数字
  99.             vTitle(nI) = vData(1, vTitleCol(nI)) '记录标题列的标题
  100.         Next
  101.     End If
  102.    
  103.     Set oDic = CreateObject("Scripting.Dictionary") '建立字典
  104.     For nRow = StartRow To UBound(vData) '从开始行StartRow开始检索数据
  105.         If IsArray(vItemCol) Then '如果Item列为数组形式,获取对应Item数组
  106.             For nI = LBound(vItemCol) To UBound(vItemCol)
  107.                 nCol = vItemCol(nI)
  108.                 vItem(nI + 1) = vData(nRow, nCol)
  109.             Next
  110.         ElseIf vItemCol > 0 Then '如果Item列非数组形式,而且列数大于0,获取对应Item
  111.             vItem = vData(nRow, vItemCol)
  112.         Else
  113.             vItem = Empty
  114.         End If
  115.         sKey = "" '初始化该行的关键字
  116.         For nI = LBound(vKeyCol) To UBound(vKeyCol) '对多列关键字进行连接
  117.             nCol = vKeyCol(nI)
  118.             If vData(nRow, nCol) = "" Then '假如存在空值,重置关键字为空,不对该行进行字典建立
  119.             '注意:该做法是针对所有关键字都不能为空进行设定,假如有其他需求,请另行修改对应逻辑
  120.                 sKey = ""
  121.                 Exit For
  122.             End If
  123.             sKey = sKey & "|" & vData(nRow, nCol)
  124.         Next
  125.         If sKey <> "" Then
  126.             If IsArray(vTitleCol) And Not bItemFirst Then '如果存在标题列数组并且不是优先直接使用Item列数据
  127.                 For nI = LBound(vTitleCol) To UBound(vTitleCol)
  128.                     nCol = vTitleCol(nI)
  129.                     If Not oDic.Exists(sKey) Then Set oDic(sKey) = CreateObject("Scripting.Dictionary")
  130.                     oDic(sKey)("|" & vTitle(nI)) = vData(nRow, nCol) '对每个标题进行字典建立
  131.                 Next
  132.             Else
  133.                 oDic(sKey) = vItem
  134.             End If
  135.         End If
  136.     Next
  137.    
  138.     Set CreateDic = oDic '返回建立的字典
  139. End Function
复制代码

在需要处理的页面添加动作响应代码
  1. Private Sub Worksheet_Change(ByVal Target As Range)
  2.     WorkSheetChange Target
  3. End Sub
复制代码

评分

7

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-11-2 11:33 | 显示全部楼层
自己占楼以便以后更新处理

TA的精华主题

TA的得分主题

发表于 2019-11-2 11:52 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2020-2-2 19:54 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2020-2-9 15:19 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
兄弟,新冠解药你研究出来没啊?没研究出来还不快去学咯

TA的精华主题

TA的得分主题

发表于 2020-2-10 09:18 | 显示全部楼层
本帖最后由 zuyong2 于 2020-2-10 10:03 编辑

在基础表中24列增加内容后出现子函数未定义。
还有如果要在里面增加营销目标(基础数据AE列,泉州办表Y列)一级下拉菜单,和在泉州办中选择省份和城市二级下拉菜单,怎么增加呢?谢谢!

QQ图片20200210091417.png

TA的精华主题

TA的得分主题

发表于 2022-5-8 08:39 来自手机 | 显示全部楼层
经典案例,标记一下,以便学习备用!
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-5-11 15:22 , Processed in 0.033843 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

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