admin管理员组文章数量:1389903
I have made a macro which should filter on a sheet, if there is match , then it should copy the data with the header (later put it into email), if there is no match ,then it should go to the next item in the loop.
Right now, even if I inly have the header after filtering, the macro copies the header instead of just moving on to ne next item,
As below, firstVisibleCellinscope should be the data visible after filtering below the header, if it is empty then the loops should move on. Unfortunately he macro copies the header instead (as per as on the attached image) of just moving on to ne next item. With items where there is a match, the macro works , copies all the data.
On Error Resume Next
' Prevent error if no visible cells exist
For I = lastRowTeams To 2 Step -1
Team = wsTeamdata.Cells(I, 1)
emailaddress = wsTeamdata.Cells(I, 2)
Worksheets("In Scope").Activate
With Worksheets("In Scope").Range("A1")
.AutoFilter Field:=18, Criteria1:=Team
End With
Set firstVisibleCellinscope = wsInscope.Range("A2:A" & lastRowInscope).SpecialCells(xlCellTypeVisible)
If firstVisibleCellinscope Is Nothing Then GoTo NextIteration
Set DatatoCopy = ActiveSheet.Range("A:K")
DatatoCopy.Copy
NextIteration:
Next I
I have made a macro which should filter on a sheet, if there is match , then it should copy the data with the header (later put it into email), if there is no match ,then it should go to the next item in the loop.
Right now, even if I inly have the header after filtering, the macro copies the header instead of just moving on to ne next item,
As below, firstVisibleCellinscope should be the data visible after filtering below the header, if it is empty then the loops should move on. Unfortunately he macro copies the header instead (as per as on the attached image) of just moving on to ne next item. With items where there is a match, the macro works , copies all the data.
On Error Resume Next
' Prevent error if no visible cells exist
For I = lastRowTeams To 2 Step -1
Team = wsTeamdata.Cells(I, 1)
emailaddress = wsTeamdata.Cells(I, 2)
Worksheets("In Scope").Activate
With Worksheets("In Scope").Range("A1")
.AutoFilter Field:=18, Criteria1:=Team
End With
Set firstVisibleCellinscope = wsInscope.Range("A2:A" & lastRowInscope).SpecialCells(xlCellTypeVisible)
If firstVisibleCellinscope Is Nothing Then GoTo NextIteration
Set DatatoCopy = ActiveSheet.Range("A:K")
DatatoCopy.Copy
NextIteration:
Next I
Share
Improve this question
edited Mar 15 at 19:31
CDP1802
16.5k2 gold badges10 silver badges18 bronze badges
asked Mar 14 at 13:12
user29975215user29975215
1
4
|
2 Answers
Reset to default 0This might be more than what you are asking for, but here's some guidelines that I think would help to make your code more reliable and efficient:
Instead of looping through cells, copy the whole range into an array and loop through the array. There's too much overhead involved when looping through cells as they are part of Excel's object model. Arrays are stored in the computer's RAM...making them much faster to access for data validation and manipulation.
To ensure that you are accessing all the data intended to be captured, try to have all of the data in a table instead of just a range. It's much easier to assign a whole table column to an array vs trying to reference a range with an address along with trying to find the last row with data populated.
Here's an example of how to apply the guidelines listed above:
Let's pretend you have a worksheet with a list of Books. There are 3 attributes/headers listed: Date, Title, and Author.
As you can see, some cells are missing data.
Applying the guidelines listed above, the first step would be to convert this range to a table. This can be done by highlighting the whole range and pressing CTRL + T:
Next step, change the name of the table to "Books" (without quotation marks):
Note: For this example, I've also changed the name of the worksheet to "Books".
Next, we can start writing the code. Let's say you want to extract each populated cell for each column and send the data to a separate subroutine that handles sending out emails. It can be written like this:
Public Sub ExportData()
Dim BooksTable As ListObject '- This is for storing the table.
Dim Buffer As Variant '- This is the array for storing the
' data extracted from the column.
Dim Column As ListColumn '- This is for storing each table
' column.
Dim Header As String
Dim Index As Long
Dim ValidItems As Collection '- This collection will be used to only
' store valid data (non-empty)
Set BooksTable = ThisWorkbook.Worksheets("Books").ListObjects("Books")
For Each Column In BooksTable.ListColumns
Header = Column.Name '- Extract the column header
Buffer = Column.DataBodyRange.Value '- Extract the column data
'Loop through each row in the array and only add valid data to the
'collection
Set ValidData = New Collection
With ValidData
For Index = LBound(Buffer, 1) To UBound(Buffer, 1)
If IsValidData(Buffer(Index, 1) Then
.Add Buffer(Index, 1)
End If
Next Index
End With
'Send header and data to email subroutine
EmailData Header, ValidData
Next Column
End Sub
'Function for validating whether the data is empty or null
Private Function IsValidData(ByVal Data As Variant) As Boolean
If IsNull(Data) Then Exit Function
If IsEmpty(Data) Then Exit Function
If Data = vbNullString Then Exit Function
IsValidData = True
End Function
'Method for sending out emails.
Private Sub EmailData(Header As String, ValidData As Collection)
'Define your email method here.
End Sub
Remove the On Error Resume Next
after setting the range to catch other errors.
Option Explicit
Sub demo()
Dim wsInscope As Worksheet, wsTeamData As Worksheet
Dim rngInScope As Range, rngHeader As Range, rngCopy As Range
Dim lastrow As Long, r As Long
Dim team As String, emailaddress As String
With ThisWorkbook
Set wsInscope = .Sheets("In Scope")
Set wsTeamData = .Sheets("TeamData")
End With
With wsInscope
.AutoFilterMode = False
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rngInScope = .Range("A2:K" & lastrow)
Set rngHeader = .Range("A1:R1")
End With
With wsTeamData
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
For r = lastrow To 2 Step -1
team = .Cells(r, 1)
emailaddress = .Cells(r, 2)
rngHeader.AutoFilter Field:=18, Criteria1:=team
' filter
With rngInScope
Set rngCopy = Nothing
' prevent error if no visible rows
On Error Resume Next
Set rngCopy = .SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If rngCopy Is Nothing Then
' no rows so skip
Debug.Print r, team, "skipped"
Else
' copy visible rows
rngCopy.Copy
Debug.Print r, team, rngCopy.Address
End If
End With
Next
End With
' clear clipboard and filters
Application.CutCopyMode = False
wsInscope.AutoFilterMode = False
MsgBox "Complete"
End Sub
本文标签: excelVBA for checking empty cells below header after filteringStack Overflow
版权声明:本文标题:excel - VBA for checking empty cells below header after filtering - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744654623a2617889.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
On Error Resume Next
? What row are your headers on? If there are no visible cells then that would raise a run-time error, and not returnNothing
tofirstVisibleCellinscope
... – Tim Williams Commented Mar 14 at 15:05firstVisibleCellinscope
to Nothing before the call to SpecialCells – Tim Williams Commented Mar 15 at 21:07