批量将工作表转换为独立的工作簿
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(总行数 / 分割行数) + 1
Else
份数 = 总行数 / 分割行数
End If
'处理每一份
j = 2
For 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 + 分割行数
Next
End 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