|
原帖由 wenwen000424 于 2010-1-25 06:26 发表
相当不错,汇总表中表头已经处理好了,A列只要加入一下合并相同内容单元格语句就可以了。希望给代码加注解。
简单点说, 就是先通过代码规范数据,然后把双表头组成字符串,用字典记录行号 、列标,再根据行号 、列标累加到总表中。
总之通用性越强,代码量越大,通用性多1点,代码量起码要多 3 点。
-
- '引用 Microsoft Scripting Runtime C:\WINDOWS\system32\scrrun.dll
- Sub 汇总()
- Dim colDIC As New Dictionary, rowDIC As New Dictionary
- '列字典 与 行字典 分别是这样的字符串 :"V360|白色" "广东|GZ02",用以确定唯一性。
- Dim rg As Range
- Dim a As Variant, b As Variant, brr() As Variant
- ' a 是 汇总后的数组 , b 是每个月的数据数组,通过 "确定区域" 函数取值并规范。brr 把b 装在一起,便于引用
- Dim k As Long, i As Long, j As Long, shcount As Integer
- Application.ScreenUpdating = False '关闭屏幕刷新 提高运行速度
- t = Timer ' 开始计时
-
- '取得每月销售表的数据区域 ,装到brr 中,并确定唯一的行标志("广东|GZ02") 和列标志("V360|白色")
- For k = 1 To Sheets.Count
- If Sheets(k).Name Like "*销量" Then
- shcount = shcount + 1
- b = 确定区域(Sheets(k))
- ReDim Preserve brr(1 To shcount)
- brr(shcount) = b
- For i = 3 To UBound(b, 2)
- colDIC(b(1, i) & "|" & b(2, i)) = 0
- Next
- For i = 3 To UBound(b, 1)
- rowDIC(b(i, 1) & "|" & b(i, 2)) = 0
- Next
- End If
- Next
- ' 取数据完成
- ' 根据列字典 与 行字典设置总表 ,设置总表格式
- Dim temp1 As Range, temp2 As Range
- With Sheets("总表")
- Sheets("总表").Cells.Delete
- crr = colDIC.Keys '取得列标志数组
- rrr = Application.WorksheetFunction.Transpose(rowDIC.Keys) '取得行标志数组
- Set temp1 = .Range("d2").Resize(1, colDIC.Count)
- temp1 = crr ' 填写列标志
- For Each rg In temp1 ' 把列标志拆分成两行
- rg.Cells(2, 1) = Split(rg, "|")(1)
- rg = Split(rg, "|")(0)
- Next
- temp1.Resize(2).Sort Key1:=.Range("D2"), Orientation:=xlSortRows ' 利用Excel排序功能进行 列标志 横向排序
- Set temp2 = .Range("b4").Resize(rowDIC.Count, 1)
- temp2 = rrr ' 填写行标志
-
- For Each rg In temp2 ' 把列标志拆分成两列
- rg.Cells(1, 2) = Split(rg, "|")(1)
- rg = Split(rg, "|")(0)
- Next
- temp2.Resize(, 2).Sort Key1:=.Range("b4"), Orientation:=xlSortColumns ' 利用Excel排序功能进行 行标志 纵向排序
-
- Range(.Range("b2"), .Cells(temp2.Rows.Count + 4, temp1.Columns.Count + 4)).Borders.Weight = 2 '总表区域画上框框边线
- .Range("b2:b3").Merge ' 合并单元格 并填上 表头
- .Range("c2:c3").Merge
- .Range("b2") = "省份"
- .Range("c2") = "销售网点"
- With .Cells(2, temp1.Columns.Count + 4).Resize(2)
- .Merge
- .Value = "合计"
- End With
- With .Cells(temp2.Rows.Count + 4, 2).Resize(, 2)
- .Merge
- .Value = "合计"
- End With
-
- Set v = temp1(1, 1)
- For Each rg In temp1.Resize(, temp1.Columns.Count + 1) ' 扩展一列 把相同型号的单元格合并
- If v <> rg Then
- s = v.Value
- Range(v, rg.Cells(1, 0)) = Empty
- Range(v, rg.Cells(1, 0)).Merge
- Range(v, rg.Cells(1, 0)) = s
- Set v = rg
- End If
- Next
- Set v = temp2(1, 1)
- For Each rg In temp2.Resize(temp2.Rows.Count + 1) ' 扩展一行 把相同地区的单元格合并 90 楼的附件中忘了这一步
- If v <> rg Then
- s = v.Value
- Range(v, rg.Cells(0, 1)) = Empty
- Range(v, rg.Cells(0, 1)).Merge
- Range(v, rg.Cells(0, 1)) = s
- Set v = rg
- End If
- Next
-
- End With
- ' '''''''' 设置总表格式结束
- a = 确定区域(Sheets("总表"), rg) ' 取得设置好的总表区域 数组 a
- For i = 3 To UBound(a, 1)
- rowDIC(a(i, 1) & "|" & a(i, 2)) = i ' 记录列标志 在数组 a 中的列序号
- Next
- For i = 3 To UBound(a, 2)
- colDIC(a(1, i) & "|" & a(2, i)) = i ' 记录行标志 在数组 a 中的行序号
- Next
- For Each b In brr '把brr中的每一项 传到 合并过程,进行合并、累加完成汇总
- 进行合并 a, b, colDIC, rowDIC
- Next
- rg.Value = a '填写汇总结果
- ' 填写合计公式,以便验证
-
- Set rg = rg.Resize(rg.Rows.Count + 1, rg.Columns.Count + 1)
-
- For i = 3 To rg.Rows.Count
- rg.Cells(i, rg.Columns.Count) = "=SUM(RC[-" & rg.Columns.Count - 3 & "]:RC[-1])"
- Next
- For i = 3 To rg.Columns.Count
- rg.Cells(rg.Rows.Count, i) = "=SUM(R[-" & rg.Rows.Count - 3 & "]C:R[-1]C)"
- Next
- Application.ScreenUpdating = True
- MsgBox Timer - t ' 运行耗时 约0.4秒, 关闭屏幕刷新后0.18秒
-
- End Sub
- Function 确定区域(sh As Worksheet, Optional c As Range) As Variant
- '这个表的格式算是相当规范的了,按照关键字 两个“合计” 可以定位区域
- Dim a As Range, b As Range
- Dim arr As Variant, v As Variant, x As Integer, y As Integer
- Set a = sh.Cells.Find(What:="合*计", After:=sh.[a1]) ' 合*计 预防 “ 合 计 ”这类非规范写法
- Set b = sh.Cells.FindNext(After:=a)
- Set c = sh.Range(sh.Cells(a.Row, b.Column), sh.Cells(b.Row - 1, a.Column - 1))
- arr = c.Value
- x = c.Row
- y = c.Column
-
- '规范输入,合并的单元格中都填上相同内容
- For i = 1 To c.Columns.Count
- If c.Cells(1, i).MergeCells Then
- If c.Cells(1, i).MergeArea.Count > 1 Then
- v = c.Cells(1, i).MergeArea
- For Each rg In c.Cells(1, i).MergeArea
- arr(rg.Row - x + 1, rg.Column - y + 1) = v(1, 1)
- Next
- i = i + c.Cells(1, i).MergeArea.Columns.Count - 1
- End If
- End If
- Next
- For i = 2 To c.Rows.Count
- If c.Cells(i, 1).MergeCells Then
- If c.Cells(i, 1).MergeArea.Count > 1 Then
- v = c.Cells(i, 1).MergeArea
- For Each rg In c.Cells(i, 1).MergeArea
- arr(rg.Row - x + 1, rg.Column - y + 1) = v(1, 1)
- Next
- i = i + c.Cells(i, 1).MergeArea.Rows.Count - 1
- End If
- End If
- Next
- 确定区域 = arr
- End Function
- Sub 进行合并(a As Variant, b As Variant, colDIC As Dictionary, rowDIC As Dictionary)
- Dim colstr As String, rowstr As String
- '根据销售表( b )中的行标志 和列标志 ,通过 行字典和列字典 找到 总表(a)中的 行号 与 列号,并累加到 总表中
- For i = 3 To UBound(b, 1)
- rowstr = b(i, 1) & "|" & b(i, 2) '组成行标志 "广东|GZ02"
- For j = 3 To UBound(b, 2)
- colstr = b(1, j) & "|" & b(2, j) '组成 列标志("V360|白色")
- r = rowDIC(rowstr) ' r 行号
- c = colDIC(colstr) ' c 列号
- a(r, c) = a(r, c) + b(i, j) ' 累加
- Next
- Next
- End Sub
-
复制代码 |
|