|
非常好!我来为您添加表内平衡验证功能。以下是完整的修改版代码:
- Sub 报表汇总()
- Dim 文件夹路径 As String
- Dim 文件列表() As String
- Dim 文件数量 As Integer
- Dim 基表序号 As String
- Dim 汇总表 As Workbook
- Dim 基表 As Workbook
- Dim i As Integer, j As Integer, k As Integer
- Dim 工作表 As Worksheet, 源工作表 As Worksheet
- Dim 不参加行 As String, 不参加列 As String
- Dim 跳过行数组() As String, 跳过列数组() As String
- Dim 行号 As Integer, 列号 As Integer
- Dim 累加文件数 As Integer
- Dim 文件名 As String
- Dim 是否平衡验证 As String
-
- '步骤1:选择文件夹并搜索xlsx文件
- With Application.FileDialog(msoFileDialogFolderPicker)
- .Title = "请选择包含报表的文件夹"
- If .Show = -1 Then
- 文件夹路径 = .SelectedItems(1)
- Else
- MsgBox "未选择文件夹,操作取消"
- Exit Sub
- End If
- End With
-
- '搜索xlsx文件
- 文件数量 = 0
- 文件名 = Dir(文件夹路径 & "\*.xlsx")
-
- Do While 文件名 <> ""
- 文件数量 = 文件数量 + 1
- ReDim Preserve 文件列表(1 To 文件数量)
- 文件列表(文件数量) = 文件名
- 文件名 = Dir
- Loop
-
- If 文件数量 = 0 Then
- MsgBox "在指定文件夹中未找到xlsx文件"
- Exit Sub
- End If
-
- '显示找到的文件
- Dim 文件列表文本 As String
- 文件列表文本 = "共找到 " & 文件数量 & " 个xlsx文件:" & vbCrLf
- For i = 1 To 文件数量
- 文件列表文本 = 文件列表文本 & i & ". " & 文件列表(i) & vbCrLf
- Next i
- MsgBox 文件列表文本
-
- '步骤2:选择基表(通过序号)
- 基表序号 = InputBox("请输入作为基表的文件序号(1-" & 文件数量 & "):", "选择基表")
- If 基表序号 = "" Then
- MsgBox "未选择基表,操作取消"
- Exit Sub
- End If
-
- '验证序号有效性
- If Not IsNumeric(基表序号) Then
- MsgBox "请输入有效的数字序号"
- Exit Sub
- End If
-
- If Val(基表序号) < 1 Or Val(基表序号) > 文件数量 Then
- MsgBox "序号必须在 1 到 " & 文件数量 & " 之间"
- Exit Sub
- End If
-
- '打开基表并复制
- Set 基表 = Workbooks.Open(文件夹路径 & "" & 文件列表(Val(基表序号)))
- 基表.SaveCopyAs 文件夹路径 & "\汇总表.xlsx"
- Set 汇总表 = Workbooks.Open(文件夹路径 & "\汇总表.xlsx")
- 基表.Close False
-
- '步骤3:为每个sheet设置不参与统计的行列
- For Each 工作表 In 汇总表.Worksheets
- '获取不参与统计的行列
- 不参加行 = InputBox("工作表 '" & 工作表.Name & "' 中不参与统计的行号(用逗号分隔,如:1,2,3,9,11):", "设置跳过行")
- 不参加列 = InputBox("工作表 '" & 工作表.Name & "' 中不参与统计的列号(用逗号分隔,如:A,B,C,D,M,P):", "设置跳过列")
-
- '解析行号数组
- If 不参加行 <> "" Then
- 跳过行数组 = Split(不参加行, ",")
- Else
- ReDim 跳过行数组(0)
- End If
-
- '解析列号数组
- If 不参加列 <> "" Then
- 跳过列数组 = Split(不参加列, ",")
- Else
- ReDim 跳过列数组(0)
- End If
- Next 工作表
-
- '步骤4:遍历所有文件进行累加
- 累加文件数 = 0
- For i = 1 To 文件数量
- If 文件列表(i) <> "汇总表.xlsx" Then
- Set 基表 = Workbooks.Open(文件夹路径 & "" & 文件列表(i))
- 累加文件数 = 累加文件数 + 1
-
- '遍历每个工作表
- For Each 工作表 In 汇总表.Worksheets
- On Error Resume Next
- Set 源工作表 = 基表.Worksheets(工作表.Name)
- If Err.Number = 0 Then
- '遍历单元格进行累加
- For j = 1 To 工作表.UsedRange.Rows.Count
- For k = 1 To 工作表.UsedRange.Columns.Count
- '检查是否需要跳过该行
- If 需要跳过(j, 跳过行数组) Or 需要跳过列(k, 跳过列数组) Then
- '跳过该单元格
- Else
- '累加数值
- Dim 源值 As Variant, 目标值 As Variant
- 源值 = 源工作表.Cells(j, k).Value
- 目标值 = 工作表.Cells(j, k).Value
-
- If IsNumeric(源值) And IsNumeric(目标值) Then
- 工作表.Cells(j, k).Value = 目标值 + 源值
- ElseIf IsNumeric(源值) And Not IsNumeric(目标值) Then
- 工作表.Cells(j, k).Value = 源值
- End If
- End If
- Next k
- Next j
- End If
- On Error GoTo 0
- Next 工作表
-
- 基表.Close False
- End If
- Next i
-
- '保存汇总表
- 汇总表.Save
-
- '步骤5:询问是否进行表内平衡验证
- 是否平衡验证 = InputBox("汇总完成!共累加了 " & 累加文件数 & " 个xlsx表格。" & vbCrLf & _
- "是否需要对汇总表进行表内平衡验证?(Y/N)", "平衡验证")
-
- If UCase(是否平衡验证) = "Y" Then
- Call 表内平衡验证(汇总表)
- End If
-
- '显示最终结果
- MsgBox "所有操作已完成!", vbInformation, "完成"
- End Sub
- '表内平衡验证函数
- Sub 表内平衡验证(汇总表 As Workbook)
- Dim 工作表 As Worksheet
- Dim 行平衡规则 As String, 列平衡规则 As String
- Dim 行规则数组() As String, 列规则数组() As String
- Dim i As Integer
- Dim 不平衡信息 As String
- Dim 验证结果 As Boolean
-
- 不平衡信息 = ""
-
- '为每个工作表设置平衡规则
- For Each 工作表 In 汇总表.Worksheets
- MsgBox "现在为工作表 '" & 工作表.Name & "' 设置平衡规则", vbInformation, "设置平衡规则"
-
- '设置行平衡规则
- 行平衡规则 = InputBox("请输入工作表 '" & 工作表.Name & "' 的行平衡规则:" & vbCrLf & _
- "格式示例:1+2+3=4+5;6+7=8+9+10" & vbCrLf & _
- "(多条规则用分号分隔)", "行平衡规则")
-
- '设置列平衡规则
- 列平衡规则 = InputBox("请输入工作表 '" & 工作表.Name & "' 的列平衡规则:" & vbCrLf & _
- "格式示例:A+B=C+D;E+F=G+H" & vbCrLf & _
- "(多条规则用分号分隔)", "列平衡规则")
-
- '验证行平衡规则
- If 行平衡规则 <> "" Then
- 行规则数组 = Split(行平衡规则, ";")
- For i = 0 To UBound(行规则数组)
- 验证结果 = 验证行平衡(工作表, 行规则数组(i))
- If Not 验证结果 Then
- 不平衡信息 = 不平衡信息 & "工作表 '" & 工作表.Name & "' 行平衡规则不满足: " & 行规则数组(i) & vbCrLf
- End If
- Next i
- End If
-
- '验证列平衡规则
- If 列平衡规则 <> "" Then
- 列规则数组 = Split(列平衡规则, ";")
- For i = 0 To UBound(列规则数组)
- 验证结果 = 验证列平衡(工作表, 列规则数组(i))
- If Not 验证结果 Then
- 不平衡信息 = 不平衡信息 & "工作表 '" & 工作表.Name & "' 列平衡规则不满足: " & 列规则数组(i) & vbCrLf
- End If
- Next i
- End If
- Next 工作表
-
- '显示平衡验证结果
- If 不平衡信息 = "" Then
- MsgBox "表内平衡验证通过!所有平衡规则都满足。", vbInformation, "平衡验证结果"
- Else
- MsgBox "表内平衡验证发现以下不平衡情况:" & vbCrLf & vbCrLf & 不平衡信息, vbExclamation, "平衡验证结果"
- End If
- End Sub
- '验证行平衡函数
- Function 验证行平衡(工作表 As Worksheet, 规则 As String) As Boolean
- Dim 规则两边() As String
- Dim 左边部分 As String, 右边部分 As String
- Dim 左边行号() As String, 右边行号() As String
- Dim i As Integer, j As Integer
- Dim 左边和 As Double, 右边和 As Double
- Dim 列数 As Integer
-
- 验证行平衡 = True
-
- '分割等号两边
- 规则两边 = Split(规则, "=")
- If UBound(规则两边) <> 1 Then
- MsgBox "规则格式错误:" & 规则
- Exit Function
- End If
-
- 左边部分 = Trim(规则两边(0))
- 右边部分 = Trim(规则两边(1))
-
- '解析左边行号
- 左边行号 = Split(左边部分, "+")
- For i = 0 To UBound(左边行号)
- 左边行号(i) = Trim(左边行号(i))
- Next i
-
- '解析右边行号
- 右边行号 = Split(右边部分, "+")
- For i = 0 To UBound(右边行号)
- 右边行号(i) = Trim(右边行号(i))
- Next i
-
- '对每一列验证平衡
- 列数 = 工作表.UsedRange.Columns.Count
- For j = 1 To 列数
- 左边和 = 0
- 右边和 = 0
-
- '计算左边和
- For i = 0 To UBound(左边行号)
- If IsNumeric(左边行号(i)) Then
- 左边和 = 左边和 + Val(工作表.Cells(Val(左边行号(i)), j).Value)
- End If
- Next i
-
- '计算右边和
- For i = 0 To UBound(右边行号)
- If IsNumeric(右边行号(i)) Then
- 右边和 = 右边和 + Val(工作表.Cells(Val(右边行号(i)), j).Value)
- End If
- Next i
-
- '检查是否平衡(允许0.01的误差)
- If Abs(左边和 - 右边和) > 0.01 Then
- 验证行平衡 = False
- Exit Function
- End If
- Next j
- End Function
- '验证列平衡函数
- Function 验证列平衡(工作表 As Worksheet, 规则 As String) As Boolean
- Dim 规则两边() As String
- Dim 左边部分 As String, 右边部分 As String
- Dim 左边列号() As String, 右边列号() As String
- Dim i As Integer, j As Integer
- Dim 左边和 As Double, 右边和 As Double
- Dim 行数 As Integer
-
- 验证列平衡 = True
-
- '分割等号两边
- 规则两边 = Split(规则, "=")
- If UBound(规则两边) <> 1 Then
- MsgBox "规则格式错误:" & 规则
- Exit Function
- End If
-
- 左边部分 = Trim(规则两边(0))
- 右边部分 = Trim(规则两边(1))
-
- '解析左边列号
- 左边列号 = Split(左边部分, "+")
- For i = 0 To UBound(左边列号)
- 左边列号(i) = Trim(左边列号(i))
- Next i
-
- '解析右边列号
- 右边列号 = Split(右边部分, "+")
- For i = 0 To UBound(右边列号)
- 右边列号(i) = Trim(右边列号(i))
- Next i
-
- '对每一行验证平衡
- 行数 = 工作表.UsedRange.Rows.Count
- For j = 1 To 行数
- 左边和 = 0
- 右边和 = 0
-
- '计算左边和
- For i = 0 To UBound(左边列号)
- 左边和 = 左边和 + Val(工作表.Cells(j, 列字母转数字(左边列号(i))).Value)
- Next i
-
- '计算右边和
- For i = 0 To UBound(右边列号)
- 右边和 = 右边和 + Val(工作表.Cells(j, 列字母转数字(右边列号(i))).Value)
- Next i
-
- '检查是否平衡(允许0.01的误差)
- If Abs(左边和 - 右边和) > 0.01 Then
- 验证列平衡 = False
- Exit Function
- End If
- Next j
- End Function
- '列字母转数字函数
- Function 列字母转数字(列字母 As String) As Integer
- Dim 结果 As Integer
- 结果 = 0
- 列字母 = UCase(列字母)
-
- Dim i As Integer
- For i = 1 To Len(列字母)
- 结果 = 结果 * 26 + (Asc(Mid(列字母, i, 1)) - Asc("A") + 1)
- Next i
-
- 列字母转数字 = 结果
- End Function
- Function 需要跳过(行号 As Integer, 跳过行数组() As String) As Boolean
- Dim i As Integer
- 需要跳过 = False
- For i = 0 To UBound(跳过行数组)
- If Val(跳过行数组(i)) = 行号 Then
- 需要跳过 = True
- Exit Function
- End If
- Next i
- End Function
- Function 需要跳过列(列号 As Integer, 跳过列数组() As String) As Boolean
- Dim i As Integer
- Dim 列字母 As String
- 需要跳过列 = False
- 列字母 = Split(Cells(1, 列号).Address(True, False), "$")(0)
-
- For i = 0 To UBound(跳过列数组)
- If UCase(跳过列数组(i)) = UCase(列字母) Then
- 需要跳过列 = True
- Exit Function
- End If
- Next i
- End Function
复制代码
新增功能说明:
1. **平衡验证询问**:汇总完成后询问用户是否进行表内平衡验证
2. **规则录入**:为每个sheet分别录入行平衡规则和列平衡规则
3. **多规则支持**:支持用分号分隔多条平衡规则
4. **详细验证**:
- 行平衡:验证指定行在各列中的数值关系
- 列平衡:验证指定列在各行中的数值关系
5. **误差容限**:允许0.01的数值误差,避免浮点数计算问题
6. **详细报告**:明确指出哪个工作表的哪条规则不平衡
使用示例:
- 行平衡规则:`1+2+3=4+5;6+7=8+9`
- 列平衡规则:`A+B=C;D+E=F+G`
这样用户就可以方便地验证汇总表的内部平衡关系了!
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 |
|