首页  >  Word

写几段代码,将总表按任意列拆分为多个工作簿

Word 2024-04-14 09:00:07 33

大家好,我是星光。
今天和大家分享的VBA小代码是:一键将总表按任意列拆分为多个工作簿

什么意思呢?举个小栗子。
如下图所示,是一张总表,现在需要按任意列,比如班级列吧,将它拆分为多个工作簿。

动画演示如下:

VBA代码如下:

Sub SplitShByArr()Dim shtAct As Worksheet, sht As Worksheet, wb As WorkbookDim rngData As Range, rngGistC As Range, rngTemp As RangeDim d As Object, aData, aKeys, vntDim intTitCount, strKey As String, strName As StringDim strADS As String, rngTit As RangeDim i As Long, j As Long, intFirstR As Long, intLastR As LongDim k As Long, x As Long, intActR As LongDim intFirstC As Long, intGistC As LongDim strPath As StringOn Error Resume Next '忽略错误继续运行程序'strPath = getStrPath() '用户选择文件保存路径If strPath = "" Then Exit Sub''获取用户输入的标题行数▼intTitCount = getTitCount()If intTitCount = False Then Exit Sub''获取拆分依据列▼Set rngGistC = GetRngGistC()If Err.Number Then GoTo errDescript'Call disAppSet '取消屏幕刷新等系统设置'Set shtAct = ActiveSheet '当前工作表If shtAct.FilterMode = True Then shtAct.Cells.AutoFilter '取消筛选状态Set rngData = shtAct.UsedRange '实际区域aData = rngData.Value '总表数据存入数组aDataintFirstC = rngData.Column '实际区域开始列intGistC = rngGistC.Column - intFirstC + 1 '依据列在aData中的序列intFirstR = rngData.Row '实际区域开始行intActR = intTitCount - intFirstR + 2 '扣除标题的数组开始行intLastR = GetintLastR(shtAct) '实际区域结束行With shtAct '标题区域Set rngTit = .Range(.Cells(1, 1), _.Cells(intTitCount, _UBound(aData, 2) + intFirstC - 1))End With''参数数组,修正异常数据▼Set d = CreateObject("scripting.dictionary") '后期字典ReDim aRef(1 To intLastR) '数组aRef,修正拆分列特殊数据For i = intActR To UBound(aData)If i > intLastR Then Exit For '如果大于有效数据最大行则退出循环vnt = aData(i, intGistC)If IsError(vnt) ThenaRef(i) = "错误值"ElseIf vnt = "" ThenaRef(i) = "空白单元格"ElseIf IsDate(vnt) Then '避免日期斜杠格式无法创建工作簿/表aRef(i) = Format(vnt, "yyyy-m-d")ElseaRef(i) = vntEnd IfstrKey = aRef(i)d(strKey) = d(strKey) + 1 '记录不同拆分关键字的数量Next''通过前8行数据来判断该列是否为特殊的文本数值For j = 1 To UBound(aData, 2) '遍历列For i = intActR To UBound(aData) '遍历前8行If i > 8 Then Exit Forvnt = aData(i, j)If IsNumeric(vnt) Then '是否数值If VarType(aData(i, j)) = 8 Then '是否文本strADS = strADS & "," & Cells(1, j + intFirstC - 1).AddressExit ForEnd IfEnd IfNextNextstrADS = Mid(strADS, 2) '需要设置文本格式的单元格地址'aKeys = d.keys '字典Keys,拆分关键字数组For i = 0 To UBound(aKeys) '遍历关键字strName = aKeys(i) '关键字ReDim aRes(1 To d(strName), 1 To UBound(aData, 2)) '结果数组k = 0 '计数器归0''筛选符合条件的记录存入结果数组For x = 1 To UBound(aRef)If aRef(x) = strName Then '如果关键字符合k = k + 1 '累加符合条件的行For j = 1 To UBound(aData, 2) '遍历列aRes(k, j) = aData(x, j) '数据存入结果数组NextEnd IfNext''建立新工作簿,存放结果数组Set wb = Workbooks.AddWith wb.Worksheets(1).Name = strName '命名If Err.Number Then '如果名称有特殊字符,则退出程序.Deletewb.Close FalseGoTo errDescriptEnd IfIf Len(strADS) Then.Range(strADS).EntireColumn.NumberFormat = "@" '特殊列设置为文本格式End IfWith .Cells(intTitCount + 1, intFirstC).Resize(k, UBound(aRes, 2)).Value = aRes '结果数组数据写入工作表End With.UsedRange.Borders.LineStyle = 1 '设置边框线rngTit.Copy.Range("a1").PasteSpecial xlPasteColumnWidths '粘贴列宽.Range("a1").PasteSpecial xlPasteAll '粘贴标题End Withwb.SaveAs strPath & strNamewb.Close FalseNexterrDescript:shtAct.SelectCall reAppSet '恢复屏幕刷新等系统设置Set d = Nothing '释放字典内存If Err.Number ThenMsgBox Err.DescriptionElseMsgBox "拆分完成。"End IfEnd Sub'用户选择文件夹路径Function getStrPath() As StringDim strPath As StringWith Application.FileDialog(msoFileDialogFolderPicker)If .Show ThenstrPath = .SelectedItems(1)Else '如用户为选中文件夹则退出Exit FunctionEnd IfEnd WithIf Right(strPath, 1) <> "" Then strPath = strPath & ""getStrPath = strPathEnd Function'获取用户输入的标题行数Function getTitCount()Dim intTitCountintTitCount = InputBox("请输入标题行的行数", _Title:="公众号Excel星球", _Default:=1)If StrPtr(intTitCount) = False ThengetTitCount = FalseExit FunctionEnd IfIf IsNumeric(intTitCount) = False ThenMsgBox "标题行的行数只能输入数字。"getTitCount = FalseExit FunctionEnd IfIf intTitCount < 0 Then MsgBox "标题行数不能为负数。" getTitCount = False Exit Function End If getTitCount = intTitCount End Function '用户选择拆分依据列 Function GetRngGistC() As Range Dim rngGistC As Range Set rngGistC = Application.InputBox("请选择拆分依据列。", _ Title:="公众号Excel星球", _ Default:=Selection.Address, _ Type:=8) If rngGistC Is Nothing Then Exit Function End If If rngGistC.Columns.Count > 1 ThenMsgBox "拆分依据列只能是单列。"Exit FunctionEnd IfSet GetRngGistC = rngGistCEnd Function'取消屏幕刷新,公式重算等Sub disAppSet()With Application.ScreenUpdating = False.Calculation = xlCalculationManual.DisplayAlerts = FalseEnd WithEnd Sub'恢复屏幕刷新等Sub reAppSet()With Application.ScreenUpdating = True.Calculation = xlCalculationAutomatic.DisplayAlerts = TrueEnd WithEnd Sub'最大数据有效行Function GetintLastR(ByVal sht As Worksheet)GetintLastR = sht.Cells.Find("*", _LookIn:=xlFormulas, SearchOrder:=xlByRows, _SearchDirection:=xlPrevious).RowEnd Function

代码详细解释见注释,概要说明如下▼

第13至第14行代码,调用getStrPath函数过程,打开文件浏览对话框,允许用户选择任意文件夹作为数据源;如果用户未选取文件夹,则退出程序。

第17至第18行代码,调用getTitCount过程,允许用户输入指定行数的标题行。

第21至第22行代码,调用GetRngGistC过程,允许用户选择拆分依据列。

第24行代码,调用disAppSet过程,取消屏幕刷新等系统设置。

第26至第34行代码将总表数据存入数组aData,并获取获取总表实际存在数据的区域、首列、拆分依据列在实际区域中的第几列、首行和尾行等重要数据。这是由于首行首列未必是第一行第一列,比如本例所示的数据,也就导致拆分依据列的列标未必是实际处理数据的列标。

第35至第39行代码计算标题区域,并赋值变量rngTit。

第41行至第58行代码遍历拆分依据列,处理异常值,比如空格、错误值和可能以”/”为格式的日期值。

第61至第72行代码通过前8行数据判断相关列是否为文本格式,避免文本型数值,比如身份证,在拆分后变形。代码将文本型数值所在的单元格地址赋值变量strADS。

第75至第113行代码按关键字拆分总表数据。其中第82至第89行代码遍历数据源将符合条件的数据存入数组aRes。第92至110行代码新建工作簿,并将结果数组的数据写入该工作簿的首个工作表,并设置标题行。

第118至第122行代码使用MsgBox函数以消息框的形式显示数据拆分结果信息。

……

示例下载,百度网盘▼
https://pan.baidu.com/s/1L2n62GIfURP09QXlIuzOwQ
提取码: tejq

拆分表格
版权声明

本文来自投稿,不代表本站立场,转载请注明出处。

分享:

扫一扫在手机阅读、分享本文