我认为这种设计将带您到达目的地...考虑一个如下所示的工作簿:
下面的脚本将在第 2 列中找到一个空白单元格(可在代码中自定义),然后根据您的规范对数据块进行操作。内置了一些健全性检查,包括唯一组的计数(您真的想要超过 25 个结果表吗?当然,该数字可以在代码中自定义),并且您是否期望对超过 10,000 行进行操作? (行检查也是可定制的。)
Option Explicit
Sub SplitDataIntoSheets()
Dim SafetyCheckUniques As Long
SafetyCheckUniques = 25 '<~ more than this number of output sheets? might be a mistake...
Dim SafetyCheckBlank As Long
SafetyCheckBlank = 10000 '<~ more than this number of rows? might be a mistake...
Dim ErrorCheck As Long
Dim Data As Worksheet, Target As Worksheet
Dim LastCol As Long, BlankCol As Long, _
GroupCol As Long, StopRow As Long, _
HeaderRow As Long, Index As Long
Dim GroupRange As Range, DataBlock As Range, _
Cell As Range
Dim GroupHeaderName As String
Dim Uniques As New Collection
'set references up-front
Set Data = ThisWorkbook.Worksheets("Data") '<~ assign the data-housing sheet
GroupHeaderName = "ID" '<~ the name of the column with our groups
BlankCol = 2 '<~ the column where our blank "stop" row is
GroupCol = 1 '<~ the column containing the groups
HeaderRow = 1 '<~ the row that has our headers
LastCol = FindLastCol(Data)
StopRow = FindFirstBlankInCol(BlankCol, HeaderRow, Data)
'sanity check: if the first blank is more than our safety number,
' we might have entered the wrong BlankCol
ErrorCheck = 0
If StopRow > SafetyCheckBlank Then
ErrorCheck = MsgBox("Dang! The first blank row in column " & _
BlankCol & " is more than " & SafetyCheckBlank & _
" rows down... Are you sure you want to run this" & _
" script?", vbYesNo, "That's a lot of rows!")
If ErrorCheck = vbNo Then Exit Sub
End If
'identify how many groups we have
With Data
Set GroupRange = .Range(.Cells(HeaderRow, GroupCol), .Cells(StopRow, GroupCol))
GroupRange.AdvancedFilter Action:=xlFilterInPlace, Unique:=True
For Each Cell In GroupRange.SpecialCells(xlCellTypeVisible)
If Cell.Value <> GroupHeaderName Then
Uniques.Add (Cell.Value)
End If
Next Cell
End With
Call ClearAllFilters(Data)
'sanity check: if there are more than 25 unique groups, do we really want
' more than 25 sheets? prompt user...
ErrorCheck = 0
If Uniques.Count > SafetyCheckUniques Then
ErrorCheck = MsgBox("Whoa! You've got " & Uniques.Count & " groups in column " & _
GroupCol & ", which is more than " & SafetyCheckUniques & _
" (which is a lot of resultant sheets). Are you sure you" & _
" want to run this script?", vbYesNo, "That's a lot of sheets!")
If ErrorCheck = vbNo Then Exit Sub
End If
'loop through the unique collection, filtering the data block
'on each unique and copying the results to a new sheet
With Data
Set DataBlock = .Range(.Cells(HeaderRow, GroupCol), .Cells(StopRow, LastCol))
End With
Application.DisplayAlerts = False
For Index = 1 To Uniques.Count
Call ClearAllFilters(Data)
'make sure the sheet doesn't exist already... delete the sheet if it's found
If DoesSheetExist(Uniques(Index)) Then
ThisWorkbook.Worksheets(CStr(Uniques(Index))).Delete
End If
'now build the sheet and copy in the data
Set Target = ThisWorkbook.Worksheets.Add
Target.Name = Uniques(Index)
DataBlock.AutoFilter Field:=GroupCol, Criteria1:=Uniques(Index)
DataBlock.SpecialCells(xlCellTypeVisible).Copy Destination:=Target.Cells(1, 1)
Next Index
Application.DisplayAlerts = True
Call ClearAllFilters(Data)
End Sub
'INPUT: a worksheet name (string)
'RETURN: true or false depending on whether or not the sheet is found in this workbook
'SPECIAL CASE: none
Public Function DoesSheetExist(dseSheetName As String) As Boolean
Dim obj As Object
On Error Resume Next
'if there is an error, sheet doesn't exist
Set obj = ThisWorkbook.Worksheets(dseSheetName)
If Err = 0 Then
DoesSheetExist = True
Else
DoesSheetExist = False
End If
On Error GoTo 0
End Function
'INPUT: a column number (long) to examine, the header row we should start in (long)
' and the worksheet that both exist in
'RETURN: the row number of the first blank
'SPECIAL CASE: return 0 if column number is <= zero,
'return 0 if the header row is <= zero,
'return 0 if sheet doesn't exist
Public Function FindFirstBlankInCol(ffbicColNumber As Long, ffbicHeaderRow As Long, _
ffbicWorksheet As Worksheet) As Long
If ffbicColNumber <= 0 Or ffbicHeaderRow <= 0 Then
FindFirstBlankInCol = 0
End If
If Not DoesSheetExist(ffbicWorksheet.Name) Then
FindFirstBlankInCol = 0
End If
'use xl down, will land on the last row before the blank
With ffbicWorksheet
FindFirstBlankInCol = .Cells(ffbicHeaderRow, ffbicColNumber).End(xlDown).Row
End With
End Function
'INPUT: a worksheet on which to identify the last column
'RETURN: the column (as a long) of the last occupied cell on the sheet
'SPECIAL CASE: return 1 if the sheet is empty
Public Function FindLastCol(flcSheet As Worksheet) As Long
If Application.WorksheetFunction.CountA(flcSheet.Cells) <> 0 Then
FindLastCol = flcSheet.Cells.Find("*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
Else
FindLastCol = 1
End If
End Function
'INPUT: target worksheet on which to clear filters safely
'TASK: clear all filters
Sub ClearAllFilters(cafSheet As Worksheet)
With cafSheet
.AutoFilterMode = False
If .FilterMode = True Then
.ShowAllData
End If
End With
End Sub