凊风 发表于 2025-9-23 16:29:26

报表汇总问题求助~~

现有P个xlsx表格置于同一文件夹中,其中每一个xlsx表格均有多个sheet(如sheet1、sheet2、sheet3),每个sheet又有N多行、M多列,需要把所有P个表格中各sheet的对应单元格数值累加起来。
    用户先建立一个空xlsx表格,然后在这个表格中运行如下宏:
                   1. 系统提示用户指定一个文件夹,然后搜索所指定文件夹中的所有xlsx表格并提示用户共找到哪些xlsx表格;
                   2.请用户指定所找到该文件夹中某一个xlsX表格做为基表(如123.xlsx),确认后系统自动完整复制此123.xlsx(含数据和表格样式)并重命名为“汇总表”;
                  3.针对汇总表中每一个sheet,列出sheet名,请用户指定此sheet中本次不参加统计累加的行号和列号(如第1.2.3行、第9、第11行,第A.B.C.D列,第M列.第P列等等,不一定是连续的行号和列号),系
                     统累加时自动跳过每一个sheet中的这些行号和列号;
               4.逐一遍览本文件夹中所有.xlsx表格中的每一个sheet,排除不需要累加的行和列,把每一单元格数据逐一累加到“汇总表”中相对应的sheet单元格中。期间如果数值为空则用0代替;
                5.统计完后提示用户共累加了多少个.xlsx表格。

FishC 发表于 2025-9-23 16:31:03

我来为您提供一个完整的VBA解决方案,可以实现报表汇总功能:


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
    Dim 不参加行 As String, 不参加列 As String
    Dim 跳过行数组() As String, 跳过列数组() As String
    Dim 行号 As Integer, 列号 As Integer
    Dim 累加文件数 As Integer
   
    '步骤1:选择文件夹并搜索xlsx文件
    With Application.FileDialog(msoFileDialogFolderPicker)
      .Title = "请选择包含报表的文件夹"
      If .Show = -1 Then
            文件夹路径 = .SelectedItems(1)
      Else
            MsgBox "未选择文件夹,操作取消"
            Exit Sub
      End If
    End With
   
    '搜索xlsx文件
    文件列表 = Dir(文件夹路径 & "\*.xlsx")
    文件数量 = 0
    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("请输入作为基表的文件名(如:123.xlsx):", "选择基表")
    If 基表文件名 = "" Then
      MsgBox "未选择基表,操作取消"
      Exit Sub
    End If
   
    '打开基表并复制
    Set 基表 = Workbooks.Open(文件夹路径 & "\" & 基表文件名)
    基表.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:显示统计结果
    MsgBox "汇总完成!共累加了 " & 累加文件数 & " 个xlsx表格。", vbInformation, "汇总结果"
End Sub

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. 在Excel中按 Alt+F11 打开VBA编辑器
2. 插入新模块,将上述代码粘贴进去
3. 返回Excel,按 Alt+F8 运行宏 报表汇总

主要功能特点:


[*]自动搜索指定文件夹中的所有xlsx文件
[*]可选择任意文件作为基表模板
[*]为每个sheet单独设置跳过的行和列
[*]自动处理空值(视为0)
[*]显示详细的统计信息
[*]保留原始表格的格式和样式


注意事项:


[*]确保所有表格的sheet名称和结构一致
[*]输入跳过行列时用逗号分隔(如:1,2,3 或 A,B,C)
[*]汇总表会保存在原文件夹中,名称为"汇总表.xlsx"


以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

凊风 发表于 2025-9-23 16:33:39

FishC 发表于 2025-9-23 16:31
我来为您提供一个完整的VBA解决方案,可以实现报表汇总功能:




'步骤2:选择基表并创建汇总表
    基表文件名 = InputBox("请输入作为基表的文件名(如:123.xlsx):", "选择基表")


能否让用户录入所找到xlsx表格的序号而不是录入表格全名?

FishC 发表于 2025-9-23 16:35:01

凊风 发表于 2025-09-23 16:33
FishC 发表于 2025-9-23 16:31
我来为您提供一个完整 ...

当然可以!我来修改代码,让用户通过输入序号来选择基表:


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
    Dim 不参加行 As String, 不参加列 As String
    Dim 跳过行数组() As String, 跳过列数组() As String
    Dim 行号 As Integer, 列号 As Integer
    Dim 累加文件数 As Integer
   
    '步骤1:选择文件夹并搜索xlsx文件
    With Application.FileDialog(msoFileDialogFolderPicker)
      .Title = "请选择包含报表的文件夹"
      If .Show = -1 Then
            文件夹路径 = .SelectedItems(1)
      Else
            MsgBox "未选择文件夹,操作取消"
            Exit Sub
      End If
    End With
   
    '搜索xlsx文件
    文件列表 = Dir(文件夹路径 & "\*.xlsx")
    文件数量 = 0
    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:显示统计结果
    MsgBox "汇总完成!共累加了 " & 累加文件数 & " 个xlsx表格。", vbInformation, "汇总结果"
End Sub

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. 输入框提示改为 "请输入作为基表的文件序号(1-文件数量):"
3. 添加了序号有效性验证
4. 使用 文件列表(Val(基表序号)) 来获取对应的文件名

现在用户只需要输入序号(如:1、2、3等)而不用输入完整的文件名,操作更加方便!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

凊风 发表于 2025-9-23 16:39:13

报错:'搜索xlsx文件
    文件列表 = Dir(文件夹路径 & "\*.xlsx")中

“文件列表 =    ”    编译错误,不能给数组赋值。

FishC 发表于 2025-9-23 16:40:42

凊风 发表于 2025-09-23 16:39
报错:'搜索xlsx文件
    文件列表 = Dir(文件夹路径 ...

您指出了一个重要的错误。在VBA中,不能直接将 `Dir` 函数的结果赋值给数组。我需要修正文件搜索部分的代码:


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
   
    '步骤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:显示统计结果
    MsgBox "汇总完成!共累加了 " & 累加文件数 & " 个xlsx表格。", vbInformation, "汇总结果"
End Sub

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. 使用单独的变量 文件名 来接收 Dir 函数的结果
3. 使用循环逐个将文件名添加到数组中
4. 修正了比较操作符(将 改为 <>)
5. 添加了缺失的变量声明 源工作表

现在代码应该可以正确编译和运行了。感谢您的指正!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

凊风 发表于 2025-9-23 17:12:11

FishC 发表于 2025-9-23 16:40
您指出了一个重要的错误。在VBA中,不能直接将 `Dir` 函数的结果赋值给数组。我需要修正文件搜索部分的 ...

能否加入表内平衡功能?
比如说全部表格累计完以后,询问用户是否需要对“汇总表”进行“表内平衡”验证?
   如果Y,就让用户逐一录入每个sheet的表内行平衡规则:
      1.行平衡规则可能不止一条,如“1+2+3+5+6;7+8=9+10+11”等等(各条行平衡规则间用“;"来分隔),要让用户确认录完全部行平衡规则后再让用户录入列平衡规则;
   2.列平衡规则也可能不止一条,如“A+B+C=D+E;F+G=H+J+M”等等(各条列平衡规则间用“;"来分隔),要让用户确认录完全部行平衡规则后再让用户录入下一个 sheet的行、列平衡规则。
   3.全部sheet的行、列平衡规则都录入完以后,系统对各sheet按用户所录入平衡规则逐一验证,如果验证不通过,要指出不平衡的行号或者列号,以供用户手动确认。

FishC 发表于 2025-9-23 17:16:05

凊风 发表于 2025-09-23 17:12
FishC 发表于 2025-9-23 16:40
您指出了一个重要的错 ...

非常好!我来为您添加表内平衡验证功能。以下是完整的修改版代码:

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 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: 报表汇总问题求助~~