我觉得这个设计会让你去你想去的地方......考虑一个工作簿,看起来像这样:
下面的脚本会发现,在第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
可以显示样本数据和您的预期结果吗?我不知道,但我觉得我仍然错过了一些东西。我在想,过滤和粘贴会做这项工作,但我可能是错的。 – L42
@ L42我完全同意,下面我提出的解决方案围绕(1)确定独特的组,(2)为每个组应用'.AutoFilter'和(3)将每个结果粘贴到新工作表 –