批量将工作表转换为独立的工作簿
Sub EachShtToWorkbook() Dim sht As Worksheet, strPath As String With Application.FileDialog(msoFileDialogFolderPicker) '选择保存工作薄的文件路径 If .Show Then strPath = .SelectedItems(1) Else Exit Sub '读取选择的文件路径,如果用户未选取路径则退出程序 End With If Right(strPath, 1) <> "\" Then strPath = strPath & "\" Application.DisplayAlerts = False '取消显示系统警告和消息,避免重名工作簿无法保存。当有重名工作簿时,会直接覆盖保存。 Application.ScreenUpdating = False '取消屏幕刷新 For Each sht In Worksheets '遍历工作表 sht.Copy '复制工作表,工作表单纯复制后,会成为活动工作薄 With ActiveWorkbook .SaveAs strPath & sht.Name, xlWorkbookDefault '保存活动工作薄到指定路径下,以当前系统默认文件格式 .Close True '关闭工作薄并保存 End With Next MsgBox "处理完成。", , "提醒" Application.ScreenUpdating = True '恢复屏幕刷新 Application.DisplayAlerts = True '恢复显示系统警告和消息End Sub
1.按任意列拆分多个表
Sub SplitShts() Dim d As Object, sht As Worksheet Dim aData, aResult, aTemp, aKeys, i&, j&, k&, x& Dim rngData As Range, rngGist As Range Dim lngTitleCount&, lngGistCol&, lngColCount& Dim rngFormat As Range, aRef, strYesOrNo As String Dim strKey As String, strTemp As String On Error Resume Next '忽略错误,程序继续运行 Set d = CreateObject("scripting.dictionary") Set rngGist = Application.InputBox("请框选拆分依据列!只能选择单列单元格区域!", Title:="提示", Type:=8) '用户选择的拆分依据列 lngGistCol = rngGist.Column '拆分依据列的列标 lngTitleCount = Val(Application.InputBox("请输入总表标题行的行数?", Default:=1)) '用户设置总表的标题行数 If lngTitleCount < 0 Then MsgBox "标题行数不能为负数,程序退出。": Exit Sub strYesOrNo = MsgBox("是否需要在分表保留总表格式?", vbYesNo) Set rngData = rngGist.Parent.UsedRange '总表的数据区域 Set rngFormat = rngGist.Parent.Cells '总表的单元格区域用于粘贴总表格式 aData = rngData.Value '数据源装入数组 lngGistCol = lngGistCol - rngData.Column + 1 '计算依据列在数组中的位置 lngColCount = UBound(aData, 2) '数据源的列数 Application.ScreenUpdating = False Application.DisplayAlerts = False ReDim aRef(1 To UBound(aData)) For i = 1 To UBound(aData) '处理依据列的异常值,空白/错误值/整行空白等 If IsError(aData(i, lngGistCol)) Then aRef(i) = "错误值" ElseIf aData(i, lngGistCol) = "" Then strTemp = "" '判断是否整行数据为空 For j = 1 To lngColCount strTemp = strTemp & aData(i, j) Next If strTemp = "" Then '如果整行为空 aRef(i) = "整行空白" Else aRef(i) = "空白单元格" End If Else strKey = aData(i, lngGistCol) aRef(i) = strKey End If Next For i = lngTitleCount + 1 To UBound(aData) strKey = aRef(i) If strKey <> "整行空白" Then If Not d.exists(strKey) Then '字典中不存在关键字时则遍历建表 d(strKey) = "" ReDim aResult(1 To UBound(aData), 1 To lngColCount) '声明一个结果数组 k = 0 For x = lngTitleCount + 1 To UBound(aData) '遍历数据源 strTemp = aRef(x) If strTemp = strKey Then '如果记录符合条件,则装入结果数组 k = k + 1 For j = 1 To lngColCount aResult(k, j) = aData(x, j) Next End If Next For Each sht In ActiveWorkbook.Worksheets '删除旧表 If sht.Name = strKey Then sht.Delete Next With Worksheets.Add(, Sheets(Sheets.Count)) '新建一个工作表 .Name = strKey .Range("a1").Resize(UBound(aData), lngColCount).NumberFormat = "@" '设置单元格为文本格式 If lngTitleCount > 0 Then .Range("a1").Resize(lngTitleCount, lngColCount) = aData '标题行 .Range("a1").Offset(lngTitleCount, 0).Resize(k, lngColCount) = aResult '写入数据 If strYesOrNo = vbYes Then '如果用户选择保留总表格式 rngFormat.Copy .Range("a1").PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, SkipBlanks:=False, Transpose:=False '复制粘贴总表的格式 .Range("a1").Offset(lngTitleCount + k, 0).Resize(UBound(aData) - k - lngTitleCount, 1).EntireRow.Delete '删除多余的格式单元格 End If .Range("a1").Select End With End If End If Next rngData.Parent.Activate '回到总表 Application.ScreenUpdating = True Application.DisplayAlerts = True Set d = Nothing Set rngData = Nothing Set rngGist = Nothing Set rngFormat = Nothing Erase aData: Erase aResult MsgBox "数据拆分完成!"End Sub
1.追加汇总各分表数据成总表【不保留分表格式】
Sub CollectData() Dim Sht As Worksheet, rng As Range, k&, n& Application.ScreenUpdating = False '取消屏幕更新 n = Val(InputBox("请输入标题的行数", "提醒")) If n < 0 Then MsgBox "标题行数不能为负数。", 64, "提示": Exit Sub '取得用户输入的标题行数,如果为负数,退出程序 Cells.ClearContents '清空当前表数据 For Each Sht In Worksheets '遍历工作表 If Sht.Name <> ActiveSheet.Name Then '如果工作表名称不等于当前表名则进行汇总动作…… Set rng = Sht.UsedRange '定义rng为表格已用区域 k = k + 1 '累计K值 If k = 1 Then '如果是首个表格,则K为1,则把标题行一起复制到汇总表 rng.Copy [a1].PasteSpecial Paste:=xlPasteValues '仅粘贴数值 Else '否则,扣除标题行后再复制黏贴到总表,只黏贴数值 rng.Offset(n).Copy Cells(ActiveSheet.UsedRange.Rows.Count + 1, 1).PasteSpecial Paste:=xlPasteValues End If End If Next [a1].Activate Application.ScreenUpdating = True '恢复屏幕刷新End Sub
2.按任意列拆分方法二
2.追加汇总分表成总表(保留分表格式)
Sub CollectDataFromShtFormat() Dim sht As Worksheet, rng As Range, k As Long, nTitleCount As Long On Error Resume Next nTitleCount = Val(InputBox("请输入标题的行数", "提醒", 1)) If nTitleCount < 0 Then MsgBox "标题行数不能为负数。", 64, "提示": Exit Sub Application.ScreenUpdating = False Cells.ClearContents '清空当前表数据 For Each sht In Worksheets '遍历工作表 If sht.Name <> ActiveSheet.Name Then '如果工作表名称不等于当前表名则进行汇总动作…… Set rng = sht.UsedRange k = k + 1 '累计K值 If k = 1 Then '如果是首个表格,则K为1,则把标题行一起复制到汇总表 sht.Cells.Copy: Range("a1").PasteSpecial Paste:=xlPasteFormats '只粘贴格式 rng.Copy: Range("a1").PasteSpecial Paste:=xlPasteValues '只粘贴数值 Else '否则,扣除标题行后再复制黏贴到总表,只黏贴数值 rng.Offset(nTitleCount).Copy With Cells(ActiveSheet.UsedRange.Rows.Count + 1, 1) .PasteSpecial Paste:=xlPasteFormats '粘贴格式 .PasteSpecial Paste:=xlPasteValues '粘贴数值 End With End If End If Next Range("a1").Activate Application.ScreenUpdating = True '恢复屏幕刷新 MsgBox "汇总OK,一共汇总了:" & k & "张工作表"End Sub
按指定行数拆分表成多个工作簿并限定列
Sub shishi2()Set 工作表 = ThisWorkbook.ActiveSheet 总行数 = 工作表.Range("A1").CurrentRegion.Rows.Count - 1 分割行数 = 3'算一下份数If 总行数 Mod 分割行数 Then 份数 = Int(总行数 / 分割行数) + 1Else份数 = 总行数 / 分割行数End If'处理每一份j = 2For i = 1 To 份数 Set 新工作簿 = Workbooks.Add 工作表.Rows("1").Copy 新工作簿.Sheets(1).Range("A1") '留下表头 工作表.Rows(j & ":" & j + 分割行数 - 1).Copy 新工作簿.Sheets(1).Range("A2") 新工作簿.Sheets(1).Columns("D:E").Delete '只要前三列 新工作簿.SaveAs "F:\" & i & ".xlsx" 新工作簿.Close Set 新工作簿 = Nothing j = j + 分割行数NextEnd Sub
合并多工作簿数据成总表
Sub CollectWorkBookDatas() Dim shtActive As Worksheet, rng As Range, shtData As Worksheet Dim nTitleRow As Long, k As Long, nLastRow As Long Dim i As Long, j As Long, nStartRow As Long Dim aData, aResult, nStarRng As Long Dim strPath As String, strFileName As String Dim strKey As String, nShtCount As Long With Application.FileDialog(msoFileDialogFolderPicker) '取得用户选择的文件夹路径 If .Show Then strPath = .SelectedItems(1) Else Exit Sub End With If Right(strPath, 1) <> "\" Then strPath = strPath & "\" strKey = InputBox("请输入需要合并的工作表所包含的关键词:" & vbCrLf & "如未填写关键词,则默认汇总全部表格数据", "提醒") If StrPtr(strKey) = 0 Then Exit Sub '如果点击了取消或者关闭按钮,则退出程序 nTitleRow = Val(InputBox("请输入标题的行数,默认标题行数为1", "提醒", 1)) If nTitleRow < 0 Then MsgBox "标题行数不能为负数。", 64, "警告": Exit Sub Set shtActive = ActiveSheet With Application .ScreenUpdating = False .DisplayAlerts = False .AskToUpdateLinks = False End With ReDim aResult(1 To 80000, 1 To 1) '声明结果数组 Cells.ClearContents '清空当前表格数据 Cells.NumberFormat = "@" '设置单元格为文本格式 strFileName = Dir(strPath & "*.xls*") '使用Dir函数遍历excel文件 Do While strFileName <> "" If strFileName <> ThisWorkbook.Name Then '避免同名文件重复打开出错 With GetObject(strPath & strFileName) '以只读'形式读取文件时,使用getobject会比workbooks.open稍快 For Each shtData In .Worksheets '遍历表 If InStr(1, shtData.Name, strKey, vbTextCompare) Then '如果表中包含关键字则进行汇总(不区分关键词字母大小写) Set rng = shtData.UsedRange If rng.Count > 1 Then '判断工作表是否存在数据…… nShtCount = nShtCount + 1 '汇总工作表的数量 nStartRow = IIf(nShtCount = 1, 1, nTitleRow + 1) '判断遍历数据源是否应该扣掉标题行 aData = rng.Value '数据区域读入数组arr If UBound(aData, 2) + 2 > UBound(aResult, 2) Then '动态调整结果数组brr的最大列数 ReDim Preserve aResult(1 To UBound(aResult), 1 To UBound(aData, 2) + 2) End If For i = nStartRow To UBound(aData) '遍历行 k = k + 1 aResult(k, 1) = strFileName '数组第一列放工作簿名称 aResult(k, 2) = shtData.Name '数组第二列放工作表名称 For j = 1 To UBound(aData, 2) '遍历列 aResult(k, j + 2) = aData(i, j) Next If k > UBound(aResult) - 1 Then '如果数据行数到达结果数组的上限,则将数据导入汇总表,并清空结果数组 With shtActive nLastRow = .Cells(Rows.Count, 1).End(xlUp).Row '获取放置来源数据的位置 If nLastRow = 1 Then '判断是否扣除标题行 nStarRng = IIf(nTitleRow = 0, 1, 0) .Range("a1").Offset(nStarRng).Resize(k, UBound(aResult, 2)) = aResult .Range("a1:b1") = Array("来源工作簿名称", "来源工作表名称") '前两列放来源工作簿和工作表名称 Else .Range("a1").Offset(nLastRow).Resize(k, UBound(aResult, 2)) = aResult '放结果数组的数据 End If End With k = 0 ReDim aResult(1 To UBound(aResult), 1 To UBound(aResult, 2)) '重新设置结果数组 End If Next End If End If Next .Close False '关闭工作簿 End With End If strFileName = Dir '下一个excel文件 Loop If k > 0 Then shtActive.Select '激活汇总表 nLastRow = Cells(Rows.Count, 1).End(xlUp).Row '放置数据的位置 If nLastRow = 1 Then '如果汇总表数据为空,说明需要汇总的数据没有超过结果数组的上限 nStarRng = IIf(nTitleRow = 0, 1, 0) Range("a1").Offset(nStarRng).Resize(k, UBound(aResult, 2)) = aResult Range("a1:b1") = Array("来源工作簿名称", "来源工作表名称") Else Range("a1").Offset(nLastRow).Resize(k, UBound(aResult, 2)) = aResult End If End If With Application .ScreenUpdating = True .DisplayAlerts = True .AskToUpdateLinks = True End With MsgBox "一共汇总完成。" & nShtCount & "个工作表", , "孙兴华"End Sub
将总表按任意列拆分成多个工作簿
Sub SplitShts()
Dim d As Object, sht As Worksheet
Dim aData, aResult, aTemp, aKeys, i&, j&, k&, x&
Dim rngData As Range, rngGist As Range, ws As Workbook
Dim lngTitleCount&, lngGistCol&, lngColCount&
Dim rngFormat As Range, aRef, strYesOrNo As String
Dim strKey As String, strTemp As String, strPath As String
On Error Resume Next '忽略错误,程序继续运行
Set d = CreateObject("scripting.dictionary")
With Application.FileDialog(msoFileDialogFolderPicker)
'用户选择保存工作簿的路径
If .Show Then strPath = .SelectedItems(1) Else Exit Sub
End With
If Right(strPath, 1) <> "\" Then strPath = strPath & "\"
Set rngGist = Application.InputBox("请框选拆分依据列!只能选择单列单元格区域!", Title:="提示", Type:=8)
'用户选择的拆分依据列
If rngGist Is Nothing Then Exit Sub
lngGistCol = rngGist.Column '拆分依据列的列标
lngTitleCount = Val(Application.InputBox("请输入总表标题行的行数?", Default:=1))
'用户设置总表的标题行数
If lngTitleCount < 0 Then MsgBox "标题行数不能为负数,程序退出。": Exit Sub
strYesOrNo = MsgBox("是否需要在分表保留总表格式?", vbYesNo)
Set rngData = rngGist.Parent.UsedRange
'总表的数据区域
Set rngFormat = rngGist.Parent.Cells
'总表的单元格区域用于粘贴总表格式
aData = rngData.Value '数据源装入数组
lngGistCol = lngGistCol - rngData.Column + 1
'计算依据列在数组中的位置
lngColCount = UBound(aData, 2)
'数据源的列数
Application.ScreenUpdating = False
Application.DisplayAlerts = False
ReDim aRef(1 To UBound(aData))
For i = 1 To UBound(aData) '处理依据列的异常值,空白/错误值/整行空白等
If IsError(aData(i, lngGistCol)) Then
aRef(i) = "错误值"
ElseIf aData(i, lngGistCol) = "" Then
strTemp = "" '判断是否整行数据为空
For j = 1 To lngColCount
strTemp = strTemp & aData(i, j)
Next
If strTemp = "" Then '如果整行为空
aRef(i) = "整行空白"
Else
aRef(i) = "空白单元格"
End If
Else
strKey = aData(i, lngGistCol)
aRef(i) = strKey
End If
Next
For i = lngTitleCount + 1 To UBound(aData)
strKey = aRef(i)
If strKey <> "整行空白" Then
If Not d.exists(strKey) Then
'字典中不存在关键字时则遍历建表
d(strKey) = ""
ReDim aResult(1 To UBound(aData), 1 To lngColCount) '声明一个结果数组
k = 0
For x = lngTitleCount + 1 To UBound(aData) '遍历数据源
strTemp = aRef(x)
If strTemp = strKey Then '如果记录符合条件,则装入结果数组
k = k + 1
For j = 1 To lngColCount
aResult(k, j) = aData(x, j)
Next
End If
Next
Set ws = Workbooks.Add
With ws.Sheets(1)
'新建一个工作簿
.Range("a1").Resize(UBound(aData), lngColCount).NumberFormat = "@"
'设置单元格为文本格式
If lngTitleCount > 0 Then .Range("a1").Resize(lngTitleCount, lngColCount) = aData
'标题行
.Range("a1").Offset(lngTitleCount, 0).Resize(k, lngColCount) = aResult
'写入数据
If strYesOrNo = vbYes Then '如果用户选择保留总表格式
rngFormat.Copy
.Range("a1").PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
'复制粘贴总表的格式
.Range("a1").Offset(lngTitleCount + k, 0).Resize(UBound(aData) - k - lngTitleCount, 1).EntireRow.Delete
'删除多余的格式单元格
End If
.Range("a1").Select
End With
ws.SaveAs strPath & strKey, xlWorkbookDefault
ws.Close False
End If
End If
Next
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Set d = Nothing
Set rngData = Nothing
Set rngGist = Nothing
Set rngFormat = Nothing
Erase aData: Erase aResult
MsgBox "数据拆分完成!"
End Sub