鱼C论坛

 找回密码
 立即注册
查看: 67|回复: 7

报表汇总问题求助~~

[复制链接]
发表于 昨天 16:29 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
现有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表格。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 昨天 16:31 | 显示全部楼层
我来为您提供一个完整的VBA解决方案,可以实现报表汇总功能:


  1. Sub 报表汇总()
  2.     Dim 文件夹路径 As String
  3.     Dim 文件列表() As String
  4.     Dim 文件数量 As Integer
  5.     Dim 基表文件名 As String
  6.     Dim 汇总表 As Workbook
  7.     Dim 基表 As Workbook
  8.     Dim i As Integer, j As Integer, k As Integer
  9.     Dim 工作表 As Worksheet
  10.     Dim 不参加行 As String, 不参加列 As String
  11.     Dim 跳过行数组() As String, 跳过列数组() As String
  12.     Dim 行号 As Integer, 列号 As Integer
  13.     Dim 累加文件数 As Integer
  14.    
  15.     '步骤1:选择文件夹并搜索xlsx文件
  16.     With Application.FileDialog(msoFileDialogFolderPicker)
  17.         .Title = "请选择包含报表的文件夹"
  18.         If .Show = -1 Then
  19.             文件夹路径 = .SelectedItems(1)
  20.         Else
  21.             MsgBox "未选择文件夹,操作取消"
  22.             Exit Sub
  23.         End If
  24.     End With
  25.    
  26.     '搜索xlsx文件
  27.     文件列表 = Dir(文件夹路径 & "\*.xlsx")
  28.     文件数量 = 0
  29.     Do While 文件列表 <> ""
  30.         文件数量 = 文件数量 + 1
  31.         ReDim Preserve 文件列表(1 To 文件数量)
  32.         文件列表(文件数量) = 文件列表
  33.         文件列表 = Dir
  34.     Loop
  35.    
  36.     If 文件数量 = 0 Then
  37.         MsgBox "在指定文件夹中未找到xlsx文件"
  38.         Exit Sub
  39.     End If
  40.    
  41.     '显示找到的文件
  42.     Dim 文件列表文本 As String
  43.     文件列表文本 = "共找到 " & 文件数量 & " 个xlsx文件:" & vbCrLf
  44.     For i = 1 To 文件数量
  45.         文件列表文本 = 文件列表文本 & i & ". " & 文件列表(i) & vbCrLf
  46.     Next i
  47.     MsgBox 文件列表文本
  48.    
  49.     '步骤2:选择基表并创建汇总表
  50.     基表文件名 = InputBox("请输入作为基表的文件名(如:123.xlsx):", "选择基表")
  51.     If 基表文件名 = "" Then
  52.         MsgBox "未选择基表,操作取消"
  53.         Exit Sub
  54.     End If
  55.    
  56.     '打开基表并复制
  57.     Set 基表 = Workbooks.Open(文件夹路径 & "" & 基表文件名)
  58.     基表.SaveCopyAs 文件夹路径 & "\汇总表.xlsx"
  59.     Set 汇总表 = Workbooks.Open(文件夹路径 & "\汇总表.xlsx")
  60.     基表.Close False
  61.    
  62.     '步骤3:为每个sheet设置不参与统计的行列
  63.     For Each 工作表 In 汇总表.Worksheets
  64.         '获取不参与统计的行列
  65.         不参加行 = InputBox("工作表 '" & 工作表.Name & "' 中不参与统计的行号(用逗号分隔,如:1,2,3,9,11):", "设置跳过行")
  66.         不参加列 = InputBox("工作表 '" & 工作表.Name & "' 中不参与统计的列号(用逗号分隔,如:A,B,C,D,M,P):", "设置跳过列")
  67.         
  68.         '解析行号数组
  69.         If 不参加行 <> "" Then
  70.             跳过行数组 = Split(不参加行, ",")
  71.         Else
  72.             ReDim 跳过行数组(0)
  73.         End If
  74.         
  75.         '解析列号数组
  76.         If 不参加列 <> "" Then
  77.             跳过列数组 = Split(不参加列, ",")
  78.         Else
  79.             ReDim 跳过列数组(0)
  80.         End If
  81.     Next 工作表
  82.    
  83.     '步骤4:遍历所有文件进行累加
  84.     累加文件数 = 0
  85.     For i = 1 To 文件数量
  86.         If 文件列表(i) <> "汇总表.xlsx" Then
  87.             Set 基表 = Workbooks.Open(文件夹路径 & "" & 文件列表(i))
  88.             累加文件数 = 累加文件数 + 1
  89.             
  90.             '遍历每个工作表
  91.             For Each 工作表 In 汇总表.Worksheets
  92.                 On Error Resume Next
  93.                 Set 源工作表 = 基表.Worksheets(工作表.Name)
  94.                 If Err.Number = 0 Then
  95.                     '遍历单元格进行累加
  96.                     For j = 1 To 工作表.UsedRange.Rows.Count
  97.                         For k = 1 To 工作表.UsedRange.Columns.Count
  98.                             '检查是否需要跳过该行
  99.                             If 需要跳过(j, 跳过行数组) Or 需要跳过列(k, 跳过列数组) Then
  100.                                 '跳过该单元格
  101.                             Else
  102.                                 '累加数值
  103.                                 Dim 源值 As Variant, 目标值 As Variant
  104.                                 源值 = 源工作表.Cells(j, k).Value
  105.                                 目标值 = 工作表.Cells(j, k).Value
  106.                                 
  107.                                 If IsNumeric(源值) And IsNumeric(目标值) Then
  108.                                     工作表.Cells(j, k).Value = 目标值 + 源值
  109.                                 ElseIf IsNumeric(源值) And Not IsNumeric(目标值) Then
  110.                                     工作表.Cells(j, k).Value = 源值
  111.                                 End If
  112.                             End If
  113.                         Next k
  114.                     Next j
  115.                 End If
  116.                 On Error GoTo 0
  117.             Next 工作表
  118.             
  119.             基表.Close False
  120.         End If
  121.     Next i
  122.    
  123.     '保存汇总表
  124.     汇总表.Save
  125.    
  126.     '步骤5:显示统计结果
  127.     MsgBox "汇总完成!共累加了 " & 累加文件数 & " 个xlsx表格。", vbInformation, "汇总结果"
  128. End Sub

  129. Function 需要跳过(行号 As Integer, 跳过行数组() As String) As Boolean
  130.     Dim i As Integer
  131.     需要跳过 = False
  132.     For i = 0 To UBound(跳过行数组)
  133.         If Val(跳过行数组(i)) = 行号 Then
  134.             需要跳过 = True
  135.             Exit Function
  136.         End If
  137.     Next i
  138. End Function

  139. Function 需要跳过列(列号 As Integer, 跳过列数组() As String) As Boolean
  140.     Dim i As Integer
  141.     Dim 列字母 As String
  142.     需要跳过列 = False
  143.     列字母 = Split(Cells(1, 列号).Address(True, False), "$")(0)
  144.    
  145.     For i = 0 To UBound(跳过列数组)
  146.         If UCase(跳过列数组(i)) = UCase(列字母) Then
  147.             需要跳过列 = True
  148.             Exit Function
  149.         End If
  150.     Next i
  151. 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 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 16:33 | 显示全部楼层
FishC 发表于 2025-9-23 16:31
我来为您提供一个完整的VBA解决方案,可以实现报表汇总功能:


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


能否让用户录入所找到xlsx表格的序号而不是录入表格全名?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 昨天 16:35 | 显示全部楼层
凊风 发表于 2025-09-23 16:33
FishC 发表于 2025-9-23 16:31
我来为您提供一个完整 ...


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


  1. Sub 报表汇总()
  2.     Dim 文件夹路径 As String
  3.     Dim 文件列表() As String
  4.     Dim 文件数量 As Integer
  5.     Dim 基表序号 As String
  6.     Dim 汇总表 As Workbook
  7.     Dim 基表 As Workbook
  8.     Dim i As Integer, j As Integer, k As Integer
  9.     Dim 工作表 As Worksheet
  10.     Dim 不参加行 As String, 不参加列 As String
  11.     Dim 跳过行数组() As String, 跳过列数组() As String
  12.     Dim 行号 As Integer, 列号 As Integer
  13.     Dim 累加文件数 As Integer
  14.    
  15.     '步骤1:选择文件夹并搜索xlsx文件
  16.     With Application.FileDialog(msoFileDialogFolderPicker)
  17.         .Title = "请选择包含报表的文件夹"
  18.         If .Show = -1 Then
  19.             文件夹路径 = .SelectedItems(1)
  20.         Else
  21.             MsgBox "未选择文件夹,操作取消"
  22.             Exit Sub
  23.         End If
  24.     End With
  25.    
  26.     '搜索xlsx文件
  27.     文件列表 = Dir(文件夹路径 & "\*.xlsx")
  28.     文件数量 = 0
  29.     Do While 文件列表 <> ""
  30.         文件数量 = 文件数量 + 1
  31.         ReDim Preserve 文件列表(1 To 文件数量)
  32.         文件列表(文件数量) = 文件列表
  33.         文件列表 = Dir
  34.     Loop
  35.    
  36.     If 文件数量 = 0 Then
  37.         MsgBox "在指定文件夹中未找到xlsx文件"
  38.         Exit Sub
  39.     End If
  40.    
  41.     '显示找到的文件
  42.     Dim 文件列表文本 As String
  43.     文件列表文本 = "共找到 " & 文件数量 & " 个xlsx文件:" & vbCrLf
  44.     For i = 1 To 文件数量
  45.         文件列表文本 = 文件列表文本 & i & ". " & 文件列表(i) & vbCrLf
  46.     Next i
  47.     MsgBox 文件列表文本
  48.    
  49.     '步骤2:选择基表(通过序号)
  50.     基表序号 = InputBox("请输入作为基表的文件序号(1-" & 文件数量 & "):", "选择基表")
  51.     If 基表序号 = "" Then
  52.         MsgBox "未选择基表,操作取消"
  53.         Exit Sub
  54.     End If
  55.    
  56.     '验证序号有效性
  57.     If Not IsNumeric(基表序号) Then
  58.         MsgBox "请输入有效的数字序号"
  59.         Exit Sub
  60.     End If
  61.    
  62.     If Val(基表序号) < 1 Or Val(基表序号) > 文件数量 Then
  63.         MsgBox "序号必须在 1 到 " & 文件数量 & " 之间"
  64.         Exit Sub
  65.     End If
  66.    
  67.     '打开基表并复制
  68.     Set 基表 = Workbooks.Open(文件夹路径 & "" & 文件列表(Val(基表序号)))
  69.     基表.SaveCopyAs 文件夹路径 & "\汇总表.xlsx"
  70.     Set 汇总表 = Workbooks.Open(文件夹路径 & "\汇总表.xlsx")
  71.     基表.Close False
  72.    
  73.     '步骤3:为每个sheet设置不参与统计的行列
  74.     For Each 工作表 In 汇总表.Worksheets
  75.         '获取不参与统计的行列
  76.         不参加行 = InputBox("工作表 '" & 工作表.Name & "' 中不参与统计的行号(用逗号分隔,如:1,2,3,9,11):", "设置跳过行")
  77.         不参加列 = InputBox("工作表 '" & 工作表.Name & "' 中不参与统计的列号(用逗号分隔,如:A,B,C,D,M,P):", "设置跳过列")
  78.         
  79.         '解析行号数组
  80.         If 不参加行 <> "" Then
  81.             跳过行数组 = Split(不参加行, ",")
  82.         Else
  83.             ReDim 跳过行数组(0)
  84.         End If
  85.         
  86.         '解析列号数组
  87.         If 不参加列 <> "" Then
  88.             跳过列数组 = Split(不参加列, ",")
  89.         Else
  90.             ReDim 跳过列数组(0)
  91.         End If
  92.     Next 工作表
  93.    
  94.     '步骤4:遍历所有文件进行累加
  95.     累加文件数 = 0
  96.     For i = 1 To 文件数量
  97.         If 文件列表(i) <> "汇总表.xlsx" Then
  98.             Set 基表 = Workbooks.Open(文件夹路径 & "" & 文件列表(i))
  99.             累加文件数 = 累加文件数 + 1
  100.             
  101.             '遍历每个工作表
  102.             For Each 工作表 In 汇总表.Worksheets
  103.                 On Error Resume Next
  104.                 Set 源工作表 = 基表.Worksheets(工作表.Name)
  105.                 If Err.Number = 0 Then
  106.                     '遍历单元格进行累加
  107.                     For j = 1 To 工作表.UsedRange.Rows.Count
  108.                         For k = 1 To 工作表.UsedRange.Columns.Count
  109.                             '检查是否需要跳过该行
  110.                             If 需要跳过(j, 跳过行数组) Or 需要跳过列(k, 跳过列数组) Then
  111.                                 '跳过该单元格
  112.                             Else
  113.                                 '累加数值
  114.                                 Dim 源值 As Variant, 目标值 As Variant
  115.                                 源值 = 源工作表.Cells(j, k).Value
  116.                                 目标值 = 工作表.Cells(j, k).Value
  117.                                 
  118.                                 If IsNumeric(源值) And IsNumeric(目标值) Then
  119.                                     工作表.Cells(j, k).Value = 目标值 + 源值
  120.                                 ElseIf IsNumeric(源值) And Not IsNumeric(目标值) Then
  121.                                     工作表.Cells(j, k).Value = 源值
  122.                                 End If
  123.                             End If
  124.                         Next k
  125.                     Next j
  126.                 End If
  127.                 On Error GoTo 0
  128.             Next 工作表
  129.             
  130.             基表.Close False
  131.         End If
  132.     Next i
  133.    
  134.     '保存汇总表
  135.     汇总表.Save
  136.    
  137.     '步骤5:显示统计结果
  138.     MsgBox "汇总完成!共累加了 " & 累加文件数 & " 个xlsx表格。", vbInformation, "汇总结果"
  139. End Sub

  140. Function 需要跳过(行号 As Integer, 跳过行数组() As String) As Boolean
  141.     Dim i As Integer
  142.     需要跳过 = False
  143.     For i = 0 To UBound(跳过行数组)
  144.         If Val(跳过行数组(i)) = 行号 Then
  145.             需要跳过 = True
  146.             Exit Function
  147.         End If
  148.     Next i
  149. End Function

  150. Function 需要跳过列(列号 As Integer, 跳过列数组() As String) As Boolean
  151.     Dim i As Integer
  152.     Dim 列字母 As String
  153.     需要跳过列 = False
  154.     列字母 = Split(Cells(1, 列号).Address(True, False), "$")(0)
  155.    
  156.     For i = 0 To UBound(跳过列数组)
  157.         If UCase(跳过列数组(i)) = UCase(列字母) Then
  158.             需要跳过列 = True
  159.             Exit Function
  160.         End If
  161.     Next i
  162. End Function
复制代码


主要修改内容:

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

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 16:39 | 显示全部楼层
报错:'搜索xlsx文件
    文件列表 = Dir(文件夹路径 & "\*.xlsx")  中

“文件列表 =    ”    编译错误,不能给数组赋值。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 昨天 16:40 | 显示全部楼层
凊风 发表于 2025-09-23 16:39
报错:'搜索xlsx文件
    文件列表 = Dir(文件夹路径 ...


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


  1. Sub 报表汇总()
  2.     Dim 文件夹路径 As String
  3.     Dim 文件列表() As String
  4.     Dim 文件数量 As Integer
  5.     Dim 基表序号 As String
  6.     Dim 汇总表 As Workbook
  7.     Dim 基表 As Workbook
  8.     Dim i As Integer, j As Integer, k As Integer
  9.     Dim 工作表 As Worksheet, 源工作表 As Worksheet
  10.     Dim 不参加行 As String, 不参加列 As String
  11.     Dim 跳过行数组() As String, 跳过列数组() As String
  12.     Dim 行号 As Integer, 列号 As Integer
  13.     Dim 累加文件数 As Integer
  14.     Dim 文件名 As String
  15.    
  16.     '步骤1:选择文件夹并搜索xlsx文件
  17.     With Application.FileDialog(msoFileDialogFolderPicker)
  18.         .Title = "请选择包含报表的文件夹"
  19.         If .Show = -1 Then
  20.             文件夹路径 = .SelectedItems(1)
  21.         Else
  22.             MsgBox "未选择文件夹,操作取消"
  23.             Exit Sub
  24.         End If
  25.     End With
  26.    
  27.     '修正:正确搜索xlsx文件
  28.     文件数量 = 0
  29.     文件名 = Dir(文件夹路径 & "\*.xlsx")
  30.    
  31.     Do While 文件名 <> ""
  32.         文件数量 = 文件数量 + 1
  33.         ReDim Preserve 文件列表(1 To 文件数量)
  34.         文件列表(文件数量) = 文件名
  35.         文件名 = Dir
  36.     Loop
  37.    
  38.     If 文件数量 = 0 Then
  39.         MsgBox "在指定文件夹中未找到xlsx文件"
  40.         Exit Sub
  41.     End If
  42.    
  43.     '显示找到的文件
  44.     Dim 文件列表文本 As String
  45.     文件列表文本 = "共找到 " & 文件数量 & " 个xlsx文件:" & vbCrLf
  46.     For i = 1 To 文件数量
  47.         文件列表文本 = 文件列表文本 & i & ". " & 文件列表(i) & vbCrLf
  48.     Next i
  49.     MsgBox 文件列表文本
  50.    
  51.     '步骤2:选择基表(通过序号)
  52.     基表序号 = InputBox("请输入作为基表的文件序号(1-" & 文件数量 & "):", "选择基表")
  53.     If 基表序号 = "" Then
  54.         MsgBox "未选择基表,操作取消"
  55.         Exit Sub
  56.     End If
  57.    
  58.     '验证序号有效性
  59.     If Not IsNumeric(基表序号) Then
  60.         MsgBox "请输入有效的数字序号"
  61.         Exit Sub
  62.     End If
  63.    
  64.     If Val(基表序号) < 1 Or Val(基表序号) > 文件数量 Then
  65.         MsgBox "序号必须在 1 到 " & 文件数量 & " 之间"
  66.         Exit Sub
  67.     End If
  68.    
  69.     '打开基表并复制
  70.     Set 基表 = Workbooks.Open(文件夹路径 & "" & 文件列表(Val(基表序号)))
  71.     基表.SaveCopyAs 文件夹路径 & "\汇总表.xlsx"
  72.     Set 汇总表 = Workbooks.Open(文件夹路径 & "\汇总表.xlsx")
  73.     基表.Close False
  74.    
  75.     '步骤3:为每个sheet设置不参与统计的行列
  76.     For Each 工作表 In 汇总表.Worksheets
  77.         '获取不参与统计的行列
  78.         不参加行 = InputBox("工作表 '" & 工作表.Name & "' 中不参与统计的行号(用逗号分隔,如:1,2,3,9,11):", "设置跳过行")
  79.         不参加列 = InputBox("工作表 '" & 工作表.Name & "' 中不参与统计的列号(用逗号分隔,如:A,B,C,D,M,P):", "设置跳过列")
  80.         
  81.         '解析行号数组
  82.         If 不参加行 <> "" Then
  83.             跳过行数组 = Split(不参加行, ",")
  84.         Else
  85.             ReDim 跳过行数组(0)
  86.         End If
  87.         
  88.         '解析列号数组
  89.         If 不参加列 <> "" Then
  90.             跳过列数组 = Split(不参加列, ",")
  91.         Else
  92.             ReDim 跳过列数组(0)
  93.         End If
  94.     Next 工作表
  95.    
  96.     '步骤4:遍历所有文件进行累加
  97.     累加文件数 = 0
  98.     For i = 1 To 文件数量
  99.         If 文件列表(i) <> "汇总表.xlsx" Then
  100.             Set 基表 = Workbooks.Open(文件夹路径 & "" & 文件列表(i))
  101.             累加文件数 = 累加文件数 + 1
  102.             
  103.             '遍历每个工作表
  104.             For Each 工作表 In 汇总表.Worksheets
  105.                 On Error Resume Next
  106.                 Set 源工作表 = 基表.Worksheets(工作表.Name)
  107.                 If Err.Number = 0 Then
  108.                     '遍历单元格进行累加
  109.                     For j = 1 To 工作表.UsedRange.Rows.Count
  110.                         For k = 1 To 工作表.UsedRange.Columns.Count
  111.                             '检查是否需要跳过该行
  112.                             If 需要跳过(j, 跳过行数组) Or 需要跳过列(k, 跳过列数组) Then
  113.                                 '跳过该单元格
  114.                             Else
  115.                                 '累加数值
  116.                                 Dim 源值 As Variant, 目标值 As Variant
  117.                                 源值 = 源工作表.Cells(j, k).Value
  118.                                 目标值 = 工作表.Cells(j, k).Value
  119.                                 
  120.                                 If IsNumeric(源值) And IsNumeric(目标值) Then
  121.                                     工作表.Cells(j, k).Value = 目标值 + 源值
  122.                                 ElseIf IsNumeric(源值) And Not IsNumeric(目标值) Then
  123.                                     工作表.Cells(j, k).Value = 源值
  124.                                 End If
  125.                             End If
  126.                         Next k
  127.                     Next j
  128.                 End If
  129.                 On Error GoTo 0
  130.             Next 工作表
  131.             
  132.             基表.Close False
  133.         End If
  134.     Next i
  135.    
  136.     '保存汇总表
  137.     汇总表.Save
  138.    
  139.     '步骤5:显示统计结果
  140.     MsgBox "汇总完成!共累加了 " & 累加文件数 & " 个xlsx表格。", vbInformation, "汇总结果"
  141. End Sub

  142. Function 需要跳过(行号 As Integer, 跳过行数组() As String) As Boolean
  143.     Dim i As Integer
  144.     需要跳过 = False
  145.     For i = 0 To UBound(跳过行数组)
  146.         If Val(跳过行数组(i)) = 行号 Then
  147.             需要跳过 = True
  148.             Exit Function
  149.         End If
  150.     Next i
  151. End Function

  152. Function 需要跳过列(列号 As Integer, 跳过列数组() As String) As Boolean
  153.     Dim i As Integer
  154.     Dim 列字母 As String
  155.     需要跳过列 = False
  156.     列字母 = Split(Cells(1, 列号).Address(True, False), "$")(0)
  157.    
  158.     For i = 0 To UBound(跳过列数组)
  159.         If UCase(跳过列数组(i)) = UCase(列字母) Then
  160.             需要跳过列 = True
  161.             Exit Function
  162.         End If
  163.     Next i
  164. End Function
复制代码


主要修正内容:

1. 修正了文件搜索部分的逻辑错误
2. 使用单独的变量 文件名 来接收 Dir 函数的结果
3. 使用循环逐个将文件名添加到数组中
4. 修正了比较操作符(将 改为 <>
5. 添加了缺失的变量声明 源工作表

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 17:12 | 显示全部楼层
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按用户所录入平衡规则逐一验证,如果验证不通过,要指出不平衡的行号或者列号,以供用户手动确认。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 昨天 17:16 | 显示全部楼层
凊风 发表于 2025-09-23 17:12
FishC 发表于 2025-9-23 16:40
您指出了一个重要的错 ...


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

  1. Sub 报表汇总()
  2.     Dim 文件夹路径 As String
  3.     Dim 文件列表() As String
  4.     Dim 文件数量 As Integer
  5.     Dim 基表序号 As String
  6.     Dim 汇总表 As Workbook
  7.     Dim 基表 As Workbook
  8.     Dim i As Integer, j As Integer, k As Integer
  9.     Dim 工作表 As Worksheet, 源工作表 As Worksheet
  10.     Dim 不参加行 As String, 不参加列 As String
  11.     Dim 跳过行数组() As String, 跳过列数组() As String
  12.     Dim 行号 As Integer, 列号 As Integer
  13.     Dim 累加文件数 As Integer
  14.     Dim 文件名 As String
  15.     Dim 是否平衡验证 As String
  16.    
  17.     '步骤1:选择文件夹并搜索xlsx文件
  18.     With Application.FileDialog(msoFileDialogFolderPicker)
  19.         .Title = "请选择包含报表的文件夹"
  20.         If .Show = -1 Then
  21.             文件夹路径 = .SelectedItems(1)
  22.         Else
  23.             MsgBox "未选择文件夹,操作取消"
  24.             Exit Sub
  25.         End If
  26.     End With
  27.    
  28.     '搜索xlsx文件
  29.     文件数量 = 0
  30.     文件名 = Dir(文件夹路径 & "\*.xlsx")
  31.    
  32.     Do While 文件名 <> ""
  33.         文件数量 = 文件数量 + 1
  34.         ReDim Preserve 文件列表(1 To 文件数量)
  35.         文件列表(文件数量) = 文件名
  36.         文件名 = Dir
  37.     Loop
  38.    
  39.     If 文件数量 = 0 Then
  40.         MsgBox "在指定文件夹中未找到xlsx文件"
  41.         Exit Sub
  42.     End If
  43.    
  44.     '显示找到的文件
  45.     Dim 文件列表文本 As String
  46.     文件列表文本 = "共找到 " & 文件数量 & " 个xlsx文件:" & vbCrLf
  47.     For i = 1 To 文件数量
  48.         文件列表文本 = 文件列表文本 & i & ". " & 文件列表(i) & vbCrLf
  49.     Next i
  50.     MsgBox 文件列表文本
  51.    
  52.     '步骤2:选择基表(通过序号)
  53.     基表序号 = InputBox("请输入作为基表的文件序号(1-" & 文件数量 & "):", "选择基表")
  54.     If 基表序号 = "" Then
  55.         MsgBox "未选择基表,操作取消"
  56.         Exit Sub
  57.     End If
  58.    
  59.     '验证序号有效性
  60.     If Not IsNumeric(基表序号) Then
  61.         MsgBox "请输入有效的数字序号"
  62.         Exit Sub
  63.     End If
  64.    
  65.     If Val(基表序号) < 1 Or Val(基表序号) > 文件数量 Then
  66.         MsgBox "序号必须在 1 到 " & 文件数量 & " 之间"
  67.         Exit Sub
  68.     End If
  69.    
  70.     '打开基表并复制
  71.     Set 基表 = Workbooks.Open(文件夹路径 & "" & 文件列表(Val(基表序号)))
  72.     基表.SaveCopyAs 文件夹路径 & "\汇总表.xlsx"
  73.     Set 汇总表 = Workbooks.Open(文件夹路径 & "\汇总表.xlsx")
  74.     基表.Close False
  75.    
  76.     '步骤3:为每个sheet设置不参与统计的行列
  77.     For Each 工作表 In 汇总表.Worksheets
  78.         '获取不参与统计的行列
  79.         不参加行 = InputBox("工作表 '" & 工作表.Name & "' 中不参与统计的行号(用逗号分隔,如:1,2,3,9,11):", "设置跳过行")
  80.         不参加列 = InputBox("工作表 '" & 工作表.Name & "' 中不参与统计的列号(用逗号分隔,如:A,B,C,D,M,P):", "设置跳过列")
  81.         
  82.         '解析行号数组
  83.         If 不参加行 <> "" Then
  84.             跳过行数组 = Split(不参加行, ",")
  85.         Else
  86.             ReDim 跳过行数组(0)
  87.         End If
  88.         
  89.         '解析列号数组
  90.         If 不参加列 <> "" Then
  91.             跳过列数组 = Split(不参加列, ",")
  92.         Else
  93.             ReDim 跳过列数组(0)
  94.         End If
  95.     Next 工作表
  96.    
  97.     '步骤4:遍历所有文件进行累加
  98.     累加文件数 = 0
  99.     For i = 1 To 文件数量
  100.         If 文件列表(i) <> "汇总表.xlsx" Then
  101.             Set 基表 = Workbooks.Open(文件夹路径 & "" & 文件列表(i))
  102.             累加文件数 = 累加文件数 + 1
  103.             
  104.             '遍历每个工作表
  105.             For Each 工作表 In 汇总表.Worksheets
  106.                 On Error Resume Next
  107.                 Set 源工作表 = 基表.Worksheets(工作表.Name)
  108.                 If Err.Number = 0 Then
  109.                     '遍历单元格进行累加
  110.                     For j = 1 To 工作表.UsedRange.Rows.Count
  111.                         For k = 1 To 工作表.UsedRange.Columns.Count
  112.                             '检查是否需要跳过该行
  113.                             If 需要跳过(j, 跳过行数组) Or 需要跳过列(k, 跳过列数组) Then
  114.                                 '跳过该单元格
  115.                             Else
  116.                                 '累加数值
  117.                                 Dim 源值 As Variant, 目标值 As Variant
  118.                                 源值 = 源工作表.Cells(j, k).Value
  119.                                 目标值 = 工作表.Cells(j, k).Value
  120.                                 
  121.                                 If IsNumeric(源值) And IsNumeric(目标值) Then
  122.                                     工作表.Cells(j, k).Value = 目标值 + 源值
  123.                                 ElseIf IsNumeric(源值) And Not IsNumeric(目标值) Then
  124.                                     工作表.Cells(j, k).Value = 源值
  125.                                 End If
  126.                             End If
  127.                         Next k
  128.                     Next j
  129.                 End If
  130.                 On Error GoTo 0
  131.             Next 工作表
  132.             
  133.             基表.Close False
  134.         End If
  135.     Next i
  136.    
  137.     '保存汇总表
  138.     汇总表.Save
  139.    
  140.     '步骤5:询问是否进行表内平衡验证
  141.     是否平衡验证 = InputBox("汇总完成!共累加了 " & 累加文件数 & " 个xlsx表格。" & vbCrLf & _
  142.                           "是否需要对汇总表进行表内平衡验证?(Y/N)", "平衡验证")
  143.    
  144.     If UCase(是否平衡验证) = "Y" Then
  145.         Call 表内平衡验证(汇总表)
  146.     End If
  147.    
  148.     '显示最终结果
  149.     MsgBox "所有操作已完成!", vbInformation, "完成"
  150. End Sub

  151. '表内平衡验证函数
  152. Sub 表内平衡验证(汇总表 As Workbook)
  153.     Dim 工作表 As Worksheet
  154.     Dim 行平衡规则 As String, 列平衡规则 As String
  155.     Dim 行规则数组() As String, 列规则数组() As String
  156.     Dim i As Integer
  157.     Dim 不平衡信息 As String
  158.     Dim 验证结果 As Boolean
  159.    
  160.     不平衡信息 = ""
  161.    
  162.     '为每个工作表设置平衡规则
  163.     For Each 工作表 In 汇总表.Worksheets
  164.         MsgBox "现在为工作表 '" & 工作表.Name & "' 设置平衡规则", vbInformation, "设置平衡规则"
  165.         
  166.         '设置行平衡规则
  167.         行平衡规则 = InputBox("请输入工作表 '" & 工作表.Name & "' 的行平衡规则:" & vbCrLf & _
  168.                             "格式示例:1+2+3=4+5;6+7=8+9+10" & vbCrLf & _
  169.                             "(多条规则用分号分隔)", "行平衡规则")
  170.         
  171.         '设置列平衡规则
  172.         列平衡规则 = InputBox("请输入工作表 '" & 工作表.Name & "' 的列平衡规则:" & vbCrLf & _
  173.                             "格式示例:A+B=C+D;E+F=G+H" & vbCrLf & _
  174.                             "(多条规则用分号分隔)", "列平衡规则")
  175.         
  176.         '验证行平衡规则
  177.         If 行平衡规则 <> "" Then
  178.             行规则数组 = Split(行平衡规则, ";")
  179.             For i = 0 To UBound(行规则数组)
  180.                 验证结果 = 验证行平衡(工作表, 行规则数组(i))
  181.                 If Not 验证结果 Then
  182.                     不平衡信息 = 不平衡信息 & "工作表 '" & 工作表.Name & "' 行平衡规则不满足: " & 行规则数组(i) & vbCrLf
  183.                 End If
  184.             Next i
  185.         End If
  186.         
  187.         '验证列平衡规则
  188.         If 列平衡规则 <> "" Then
  189.             列规则数组 = Split(列平衡规则, ";")
  190.             For i = 0 To UBound(列规则数组)
  191.                 验证结果 = 验证列平衡(工作表, 列规则数组(i))
  192.                 If Not 验证结果 Then
  193.                     不平衡信息 = 不平衡信息 & "工作表 '" & 工作表.Name & "' 列平衡规则不满足: " & 列规则数组(i) & vbCrLf
  194.                 End If
  195.             Next i
  196.         End If
  197.     Next 工作表
  198.    
  199.     '显示平衡验证结果
  200.     If 不平衡信息 = "" Then
  201.         MsgBox "表内平衡验证通过!所有平衡规则都满足。", vbInformation, "平衡验证结果"
  202.     Else
  203.         MsgBox "表内平衡验证发现以下不平衡情况:" & vbCrLf & vbCrLf & 不平衡信息, vbExclamation, "平衡验证结果"
  204.     End If
  205. End Sub

  206. '验证行平衡函数
  207. Function 验证行平衡(工作表 As Worksheet, 规则 As String) As Boolean
  208.     Dim 规则两边() As String
  209.     Dim 左边部分 As String, 右边部分 As String
  210.     Dim 左边行号() As String, 右边行号() As String
  211.     Dim i As Integer, j As Integer
  212.     Dim 左边和 As Double, 右边和 As Double
  213.     Dim 列数 As Integer
  214.    
  215.     验证行平衡 = True
  216.    
  217.     '分割等号两边
  218.     规则两边 = Split(规则, "=")
  219.     If UBound(规则两边) <> 1 Then
  220.         MsgBox "规则格式错误:" & 规则
  221.         Exit Function
  222.     End If
  223.    
  224.     左边部分 = Trim(规则两边(0))
  225.     右边部分 = Trim(规则两边(1))
  226.    
  227.     '解析左边行号
  228.     左边行号 = Split(左边部分, "+")
  229.     For i = 0 To UBound(左边行号)
  230.         左边行号(i) = Trim(左边行号(i))
  231.     Next i
  232.    
  233.     '解析右边行号
  234.     右边行号 = Split(右边部分, "+")
  235.     For i = 0 To UBound(右边行号)
  236.         右边行号(i) = Trim(右边行号(i))
  237.     Next i
  238.    
  239.     '对每一列验证平衡
  240.     列数 = 工作表.UsedRange.Columns.Count
  241.     For j = 1 To 列数
  242.         左边和 = 0
  243.         右边和 = 0
  244.         
  245.         '计算左边和
  246.         For i = 0 To UBound(左边行号)
  247.             If IsNumeric(左边行号(i)) Then
  248.                 左边和 = 左边和 + Val(工作表.Cells(Val(左边行号(i)), j).Value)
  249.             End If
  250.         Next i
  251.         
  252.         '计算右边和
  253.         For i = 0 To UBound(右边行号)
  254.             If IsNumeric(右边行号(i)) Then
  255.                 右边和 = 右边和 + Val(工作表.Cells(Val(右边行号(i)), j).Value)
  256.             End If
  257.         Next i
  258.         
  259.         '检查是否平衡(允许0.01的误差)
  260.         If Abs(左边和 - 右边和) > 0.01 Then
  261.             验证行平衡 = False
  262.             Exit Function
  263.         End If
  264.     Next j
  265. End Function

  266. '验证列平衡函数
  267. Function 验证列平衡(工作表 As Worksheet, 规则 As String) As Boolean
  268.     Dim 规则两边() As String
  269.     Dim 左边部分 As String, 右边部分 As String
  270.     Dim 左边列号() As String, 右边列号() As String
  271.     Dim i As Integer, j As Integer
  272.     Dim 左边和 As Double, 右边和 As Double
  273.     Dim 行数 As Integer
  274.    
  275.     验证列平衡 = True
  276.    
  277.     '分割等号两边
  278.     规则两边 = Split(规则, "=")
  279.     If UBound(规则两边) <> 1 Then
  280.         MsgBox "规则格式错误:" & 规则
  281.         Exit Function
  282.     End If
  283.    
  284.     左边部分 = Trim(规则两边(0))
  285.     右边部分 = Trim(规则两边(1))
  286.    
  287.     '解析左边列号
  288.     左边列号 = Split(左边部分, "+")
  289.     For i = 0 To UBound(左边列号)
  290.         左边列号(i) = Trim(左边列号(i))
  291.     Next i
  292.    
  293.     '解析右边列号
  294.     右边列号 = Split(右边部分, "+")
  295.     For i = 0 To UBound(右边列号)
  296.         右边列号(i) = Trim(右边列号(i))
  297.     Next i
  298.    
  299.     '对每一行验证平衡
  300.     行数 = 工作表.UsedRange.Rows.Count
  301.     For j = 1 To 行数
  302.         左边和 = 0
  303.         右边和 = 0
  304.         
  305.         '计算左边和
  306.         For i = 0 To UBound(左边列号)
  307.             左边和 = 左边和 + Val(工作表.Cells(j, 列字母转数字(左边列号(i))).Value)
  308.         Next i
  309.         
  310.         '计算右边和
  311.         For i = 0 To UBound(右边列号)
  312.             右边和 = 右边和 + Val(工作表.Cells(j, 列字母转数字(右边列号(i))).Value)
  313.         Next i
  314.         
  315.         '检查是否平衡(允许0.01的误差)
  316.         If Abs(左边和 - 右边和) > 0.01 Then
  317.             验证列平衡 = False
  318.             Exit Function
  319.         End If
  320.     Next j
  321. End Function

  322. '列字母转数字函数
  323. Function 列字母转数字(列字母 As String) As Integer
  324.     Dim 结果 As Integer
  325.     结果 = 0
  326.     列字母 = UCase(列字母)
  327.    
  328.     Dim i As Integer
  329.     For i = 1 To Len(列字母)
  330.         结果 = 结果 * 26 + (Asc(Mid(列字母, i, 1)) - Asc("A") + 1)
  331.     Next i
  332.    
  333.     列字母转数字 = 结果
  334. End Function

  335. Function 需要跳过(行号 As Integer, 跳过行数组() As String) As Boolean
  336.     Dim i As Integer
  337.     需要跳过 = False
  338.     For i = 0 To UBound(跳过行数组)
  339.         If Val(跳过行数组(i)) = 行号 Then
  340.             需要跳过 = True
  341.             Exit Function
  342.         End If
  343.     Next i
  344. End Function

  345. Function 需要跳过列(列号 As Integer, 跳过列数组() As String) As Boolean
  346.     Dim i As Integer
  347.     Dim 列字母 As String
  348.     需要跳过列 = False
  349.     列字母 = Split(Cells(1, 列号).Address(True, False), "$")(0)
  350.    
  351.     For i = 0 To UBound(跳过列数组)
  352.         If UCase(跳过列数组(i)) = UCase(列字母) Then
  353.             需要跳过列 = True
  354.             Exit Function
  355.         End If
  356.     Next i
  357. 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 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-9-24 10:18

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表