楼主 kevinchengcw |
Q: 如何用vba代码对进销数据进行汇总和排名? A: 实现代码如下:- Sub test()
- Dim Dic As Object, Arr(), Arrt(), Arr2(), Result(), N&, I&, T&, A&, D#, C&, Str$, Str2$
- Set Dic = CreateObject("scripting.dictionary") '创建字典项目,用于快速汇总数据结果
- With Worksheets("进货数据") '将进货数据区内容读取到数组中
- Arr = .[a1].Resize(.Cells(.Rows.Count, 2).End(3).Row, 12).Value
- End With
- For N = LBound(Arr) + 1 To UBound(Arr) '循环进货数据各行进行数据汇总
- Str = Arr(N, 2) & vbTab & Arr(N, 4)
- Str2 = Str & vbTab & "总进货数量" '组合不同的key来储存不同的数据内容
- If Dic.exists(Str2) Then Dic(Str2) = Dic(Str2) + Arr(N, 7) Else Dic(Str2) = Arr(N, 7)
- Str2 = Str & vbTab & Arr(N, 1) & vbTab & 1 '后面的数字代表结果表中对应区下方的不同列,以克服文本的不统一(使用前提:表格格式固定且有规律)
- If Dic.exists(Str2) Then Dic(Str2) = Dic(Str2) + Arr(N, 7) Else Dic(Str2) = Arr(N, 7)
- Str2 = Str & vbTab & Arr(N, 1) & vbTab & 3
- If Dic.exists(Str2) Then Dic(Str2) = Dic(Str2) + Arr(N, 7) Else Dic(Str2) = Arr(N, 7)
- Next N
- With Worksheets("销售数据") '将销售数据区内容读取到数组中
- Arr = .[a1].Resize(.Cells(.Rows.Count, 2).End(3).Row, 11).Value
- End With
- For N = LBound(Arr) + 1 To UBound(Arr) '循环销售数据各行进行数据汇总
- Str = Arr(N, 7) & vbTab & Arr(N, 9) '组合不同的key来储存不同的数据内容
- Str2 = Str & vbTab & Arr(N, 1) & vbTab & 2 '后面的数字代表结果表中对应区下方的不同列,以克服文本的不统一(使用前提:表格格式固定且有规律)
- If Dic.exists(Str2) Then Dic(Str2) = Dic(Str2) + Arr(N, 11) Else Dic(Str2) = Arr(N, 11)
- Str2 = Str & vbTab & "总销售数量" '另添加当前区域总销售量数据统计
- If Dic.exists(Str2) Then Dic(Str2) = Dic(Str2) + Arr(N, 11) Else Dic(Str2) = Arr(N, 11)
- Next N
- With Worksheets("跟踪模板") '到跟踪模板工作表来处理结果数据
- .Range("e3", .Cells.SpecialCells(xlCellTypeLastCell)).ClearContents '清空结果数据区内容(因本例仅要求替代公式效果,故未添加自动获取销售商品清单功能)
- ReDim Arr(1 To .Cells(.Rows.Count, 3).End(3).Row - 2, 1 To 1) '初始化结果数据数组
- For N = 5 To .Cells(1, .Columns.Count).End(1).Column '循环数据区首行
- If .Cells(1, N) <> "" Then '如果单元格不为空(因有合并单元格,合并区域除首单元格外,其余都会是空)
- For I = 3 To .Cells(.Rows.Count, 3).End(3).Row '循环下方对应的数据行单元格
- If N = 5 Then Arr(I - 2, 1) = .Cells(I, 2).Value '当处理第一列时添加男女分类到数组中,用于后期排名统计
- Str = .Cells(I, 3).Value & vbTab & .Cells(I, 4).Value & vbTab & .Cells(1, N).Value '组合关键字
- If .Cells(1, N).Value Like "*区" Then '判断所处区域,如果是各区列表区,则
- If I = 3 Then ReDim Preserve Arr(LBound(Arr) To UBound(Arr), LBound(Arr, 2) To UBound(Arr, 2) + 1) '第一次处理当前区数据时在数组中添加对应数据区
- With .Cells(I, N) '开始相对当前循环到的单元格区域进行数据处理
- For T = 1 To 3 '循环各列
- Str2 = Str & vbTab & T
- If Dic.exists(Str2) Then '如果对应数据存在,则提取
- .Offset(, T - 1).Value = Dic(Str2)
- If T = 2 Then Arr(I - 2, UBound(Arr, 2)) = Dic(Str2) '如果是销售量列,则将数据添加到数组中
- End If
- Next T
- .Offset(, 3).Value = .Value - .Offset(, 1).Value - .Offset(, 2).Value '统计库存
- End With
- Else '如果不是各区数据区,则
- If Dic.exists(Str) Then '如果存在对应字典项目
- .Cells(I, N).Value = Dic(Str) '对应数据写入当前循环到的单元格
- If .Cells(1, N).Value = "总销售数量" Then '如果第一行当前循环到的列数据内容是"总销售数量",则
- If I = 3 Then ReDim Preserve Arr(LBound(Arr) To UBound(Arr), LBound(Arr, 2) To UBound(Arr, 2) + 1) '第一次循环到时添加对应数组列
- Arr(I - 2, UBound(Arr, 2)) = Dic(Str) '对应数据写入数组
- End If
- End If
- End If
- Next I
- End If
- If .Cells(1, N).Value = "总销售数量" Then '总销售量处理完成后,记录下下一列的列号,退出数据区循环
- C = N + 1
- Exit For
- End If
- Next N
- For N = LBound(Arr, 2) + 1 To UBound(Arr, 2) '循环数组第二列开始的各列,进行排名统计
- Dic.RemoveAll '清空字典内容
- For I = LBound(Arr) To UBound(Arr) '统计男女分类数据
- If Dic.exists(Arr(I, 1)) Then
- Arrt = Dic(Arr(I, 1))
- ReDim Preserve Arrt(LBound(Arrt) To UBound(Arrt) + 1)
- Arrt(UBound(Arrt)) = Arr(I, N)
- Dic(Arr(I, 1)) = Arrt
- Else
- ReDim Arrt(1 To 1)
- Arrt(1) = Arr(I, N)
- Dic(Arr(I, 1)) = Arrt
- End If
- Next I
- Arr2 = Dic.keys '提取字典项目
- For I = LBound(Arr2) To UBound(Arr2) '循环字典中各项(实际只男女两个分类)
- Arrt = Dic(Arr2(I)) '提取对应的数据数组
- If UBound(Arrt) > 1 Then '如果数组内容多于一项,则进行排序
- For T = LBound(Arrt) To UBound(Arrt) - 1
- For A = T + 1 To UBound(Arrt)
- If Val(Arrt(A)) > Val(Arrt(T)) Then
- A = Val(Arrt(A))
- Arrt(A) = Val(Arrt(T))
- Arrt(T) = A
- End If
- Next A
- Str = Arr2(I) & vbTab & Arrt(T) '排充结果与性别组合添加到字典,并记录对应的排名
- Dic(Str) = T
- Next T
- Dic(Arr2(I) & vbTab & Arrt(T)) = T
- Else
- Dic(Arr2(I) & vbTab & Arrt(1)) = 1
- End If
- Next I
- For I = LBound(Arr) To UBound(Arr) '循环将数组中对应的数值转换为排名
- Str = Arr(I, 1) & vbTab & Arr(I, N)
- Arr(I, N) = Dic(Str)
- Next I
- Next N
- ReDim Arrt(LBound(Arr) To UBound(Arr), LBound(Arr, 2) To UBound(Arr, 2) - 1) '重写义最终排名结果数组Arrt,比预处理数组Arr少了姓名一列
- For N = LBound(Arr) To UBound(Arr) '将排名结果写入最终排名结果数组Arrt
- For I = LBound(Arr, 2) + 1 To UBound(Arr, 2)
- Arrt(N, I - 1) = Arr(N, I)
- Next I
- Next N
- .Cells(3, C).Resize(UBound(Arrt), UBound(Arrt, 2)) = Arrt '排名结果写入数据区
- End With
- Set Dic = Nothing '清空字典项目
- End Sub
详见附件及素材源帖。
模版 - 副本.rar |