楼主 kevinchengcw |
Q: 如何用vba代码依群组统计不同报表中的内容并生成汇总表及汇总工作簿? A: 代码如下:
- Sub test()
- Dim Dic As Object, Dic2 As Object, Wb As Workbook, Ws As Worksheet, NewWs As Worksheet, Rng1 As Range, Rng2 As Range, Rng3 As Range, RT As Range, RV As Range, RH As Range, FN$, Str$, N&, Arr(), I&
- On Error Resume Next '加上防错语句
- Application.ScreenUpdating = False '关闭屏幕刷新,提高处理速度
- Set Dic = CreateObject("scripting.dictionary") '创建字典项目
- Set Dic2 = CreateObject("scripting.dictionary")
- For Each Ws In Worksheets '将现有表名添加到字典2中,用于复制前判断是否已存在该表名
- Dic2.Add Ws.Name, ""
- Next Ws
- FN = Dir(ThisWorkbook.Path & "\*.xls") '枚举当前目录下的excel文档
- Do While FN <> ""
- If FN <> ThisWorkbook.Name Then '如果当前枚举到的文件名不是当前工作簿的文件名,则进行下述操作
- Set Wb = GetObject(ThisWorkbook.Path & "\" & FN) '后台打开该工作簿,并赋值给工作簿变量
- With Wb
- For Each Ws In .Worksheets '循环该工作簿中各表
- With Ws
- If Not .Cells.Find("坐席") Is Nothing Then '如果存在关键字,则说明有有效数据
- If Not Dic2.exists(.Name) Then '判断是否已有该工作表名,没有的话,则在当前工作簿中新添加一个表,并复制源工作表中的数据区域到新表,并将新表的表名命名为源工作簿的无后扩展名的文件名
- Set NewWs = ThisWorkbook.Worksheets.Add
- NewWs.Name = Mid(Wb.Name, 1, InStrRev(Wb.Name, ".") - 1)
- .UsedRange.Copy NewWs.Range(.UsedRange.Address)
- End If
- Set Rng1 = .Cells.Find("坐席") '取得关键字所在的单元格的位置
- For Each RV In .Range(Rng1.Offset(1), .Cells(.Rows.Count, Rng1.Column).End(3).Offset(-2)) '循环姓名数据区
- If RV.Offset(, -1) <> "" Then N = RV.Offset(, -1).Value '提取组别号
- If RV <> "" And Not RV.Value Like "*合计*" Then '如果不是合计栏,则开始数据添加
- Set Rng2 = .Cells.Find("死档") '取得标题行最后单元格位置
- For Each RH In .Range(.Cells(Rng2.Row, Rng1.Offset(, 1).Column), Rng2.Offset(, -1)) '循环标题行各单元格
- If Not RH.Value Like "*率*" And Not RH.Value Like "*计*" Then '如果当前标题行单元格不是公式列,则添加数据
- Str = N & vbTab & RV.Value & vbTab & RH.Value '先配制字典的key(组别+姓名+标题行内容)
- If Dic.exists(Str) Then '如果已有这样的key存在,则进行合计
- Dic(Str) = Dic(Str) + .Cells(RV.Row, RH.Column).Value
- Else '没有则进行添加
- Dic.Add Str, .Cells(RV.Row, RH.Column).Value
- End If
- End If
- Next RH
- End If
- Next RV
- End If
- End With
- Next Ws
- End With
- Wb.Close False '关闭工作簿
- End If
- FN = Dir '循环到下一文件
- Loop
- Dic2.RemoveAll '清空字典2,用于下一步存放组别数据
- With Worksheets("汇总") '设置一下汇总表的位置并激活
- .Move before:=Worksheets(1)
- .Activate
- End With
- Rows("3:" & Rows.Count).Clear '清空旧的数据区内容
- Set Rng1 = Cells.Find("坐席") '取得标题行首尾位置
- Set Rng2 = Cells.Find("死档")
- Set RV = Rng1.Offset(1) '设置数据起始单元格位置
- Application.Calculation = xlCalculationManual '设置工作表重算为手动(因为会写入大量公式)
- Do While Dic.Count <> 0 '先判断字典中有没有数据,防止出错
- Arr = Dic.keys '提取字典keys到数组中
- I = Split(Arr(0), vbTab)(0) '取得第一个元素的组别并赋值给变量
- Set Rng3 = RV '设置单元格变量为当前单元格(因该变量在后期合并组别单元格时作为合并区域起始单元格位置使用)
- RV.Offset(, -1) = I '设置组别单元格的值为当前取得的值
- For N = LBound(Arr) To UBound(Arr) '循环提取字典各key值
- If Split(Arr(N), vbTab)(0) = I And Not Dic2.exists(Split(Arr(N), vbTab)(1)) Then Dic2.Add Split(Arr(N), vbTab)(1), "" '如果组别相同且姓名未出现在字典2中则添加
- Next N
- RV.Resize(Dic2.Count, 1) = Application.Transpose(Dic2.keys) '将字典2的数据转置到姓名区
- For Each RT In RV.Resize(Dic2.Count, 1) '循环提取姓名区内容
- For Each RH In Range(Rng1.Offset(, 1), Rng2) '循环提取标题区内容
- Str = I & vbTab & RT.Value & vbTab & RH.Value '组合key用于判断
- If Dic.exists(Str) Then '如果存在该key及对对应单元格赋值,并清除相应字典项
- Cells(RT.Row, RH.Column) = Dic(Str)
- Dic.Remove Str
- End If
- Next RH
- Next RT
- Set RV = RV.Offset(Dic2.Count) '姓名区单元格下移姓名区下一行位置
- Dic2.RemoveAll '清空字典2用于下一次处理
- With RV '写入合计行的内容,格式及公式
- .Value = "合计"
- .Interior.Color = vbYellow
- End With
- With Range(RV.Offset(, 1), Cells(RV.Row, Rng2.Column))
- .FormulaR1C1 = "=sum(R[" & Rng3.Row - RV.Row & "]C:R[-1]C)"
- .Interior.Color = vbYellow
- End With
- Set RV = RV.Offset(1)
- Loop
- With RV '全部执行完成后写入总计行数据
- .Value = "总计"
- .Interior.Color = vbRed
- End With
- With Range(RV.Offset(, 1), Cells(RV.Row, Rng2.Column))
- .FormulaR1C1 = "=sum(R[" & Rng1.Row - RV.Row & "]C:R[-1]C)"
- .Interior.Color = vbRed
- End With
- Set Rng3 = Rng1.Offset(1, -1)
- Application.DisplayAlerts = False '关闭警告提示,进行组别区单元格合并操作
- For Each RT In Range(Rng1.Offset(2, -1), RV.Offset(, -1))
- If RT <> "" Or RT.Offset(1).Row > RV.Row Then
- If Range(Rng3, RT.Offset(-1)).Cells.Count > 2 Then Range(Rng3, RT.Offset(-1)).Merge
- Set Rng3 = RT
- End If
- Next RT
- Application.DisplayAlerts = True '打开警告提示
- Set Rng3 = Cells(Rows.Count, Rng1.Column).End(3) '取得最后一行数据的位置,用于写入公式计算列
- Range(Rng1.Offset(, -1), Cells(Rng3.Row, Rng2.Column)).Borders.LineStyle = 1 '加上边框
- For Each RH In Range(Rng1.Offset(, 1), Rng2)
- If RH.Value Like "*率*" Then
- With Range(RH.Offset(1), Cells(Rng3.Row, RH.Column))
- .Interior.Color = vbYellow
- .NumberFormatLocal = "0.0%"
- .FormulaR1C1 = "=IF(RC[-2]=0,0,RC[-1]/RC[-2])"
- End With
- ElseIf RH.Value Like "*计*" Then
- With Range(RH.Offset(1), Cells(Rng3.Row, RH.Column))
- .Interior.Color = vbYellow
- .FormulaR1C1 = "=RC[-1]+RC[-2]"
- End With
- End If
- Next RH
- Application.Calculation = xlCalculationAutomatic '恢复计算模式为自动重算
- Set Dic = Nothing '清空字典项目
- Set Dic2 = Nothing
- Application.ScreenUpdating = True '打开屏幕刷新
- MsgBox "处理完成" '显示提示信息
- End Sub
补充内容 (2012-1-14 20:24): 附件补在三楼 |