Trying to filter data and display it on another sheet, however the data isn't fully copied - excel

im trying to filter some data(sheet="Imported Data") and paste the data that matches to a sheet("Test"). However somehow it doesn't fully work. I have asked this kinda question before, but I've been trying for 3hours now but I can't get it done!
What I want:
- There are 3 single cells which the user can fill in which are the criteria(Collection , System and Tag)
- Collection is a MUST fill in for the user, the others can be left blank if the user wants it so. The result must be the entire row(Column A,B and C)
- If one, two or three criteria are filled in the chosen criterias must all match to copy to the new sheet (so if one criteria is left blank, the result should be all all three criteria. But the one not filled in can be any value).
- If all criteria match, from the sheet="Imported Data" also the value of column E must be copied to sheet("Test"),
this value of column E must be the cell which is in the same row as the matched values.
If you have any questions, fill free to ask... it's a bit hard to explain.
Thanks for the help in advance! This is what I have now:
Option Explicit
Sub FilterButton()
Dim SrcSheet As Worksheet, DestSheet As Worksheet
Dim SourceRange As Range
Dim aCell As Range, bCell As Range
Dim iLastRow As Long, zLastRow As Long
Dim Collection As String, System As String, Tag As String
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
'~~> Set your sheet
Set DestSheet = Sheets("Test")
Set SrcSheet = Sheets("Imported Data")
'~~> Find Last Row in Col A in the source sheet
With SrcSheet
iLastRow = .Range("A" & .Rows.Count).End(xlDown).Row
End With
'~~> Find Last "Available Row for Output" in Col A in the destination sheet
With DestSheet
zLastRow = .Range("A" & .Rows.Count).End(xlUp).Row + 1
End With
'~~> Set your ranges
Set SourceRange = SrcSheet.Range("A2:A" & iLastRow)
'~~> Search values
Collection = Trim(Range("lblImportCollection").Value)
System = Trim(Range("lblImportSystem").Value)
Tag = Trim(Range("lblImportTag").Value)
With SourceRange
'~~> Match 1st Criteria
Set aCell = .Find(What:=Collection, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
'~~> If found
If Not aCell Is Nothing Then
Set bCell = aCell
'~~> Copy A:C. Then match for Crit B and Crit C and remove what is not required
DestSheet.Range("A" & zLastRow & ":" & "C" & zLastRow).Value = _
SrcSheet.Range("A" & aCell.Row & ":" & "C" & aCell.Row).Value
'~~> Match 2nd Criteria
If Len(Trim(System)) = 0 Or _
aCell.Offset(, 1).Value <> System Then _
DestSheet.Range("B" & zLastRow).ClearContents
MsgBox System & " Not Found"
'~~> Match 3rd Criteria
If Len(Trim(Tag)) = 0 Or _
aCell.Offset(, 2).Value <> Tag Then _
DestSheet.Range("C" & zLastRow).ClearContents
MsgBox Tag & " Not Found"
If Not DestSheet.Range("B" & zLastRow).ClearContents Or _
DestSheet.Range("C" & zLastRow).ClearContents Then
'~~> Copy E:E. Then match for Crit B and Crit C and remove what is not required
DestSheet.Range("D" & zLastRow & ":" & "D" & zLastRow).Value = _
SrcSheet.Range("E" & aCell.Row & ":" & "E" & aCell.Row).Value
End If
'~~> Increase last row by 1 for output
zLastRow = zLastRow + 1
Do
Set aCell = .FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
'~~> Match 2nd Criteria
If Len(Trim(System)) = 0 Or _
aCell.Offset(, 1).Value <> System Then _
DestSheet.Range("B" & zLastRow).ClearContents
'~~> Match 3rd Criteria
If Len(Trim(Tag)) = 0 Or _
aCell.Offset(, 2).Value <> Tag Then _
DestSheet.Range("C" & zLastRow).ClearContents
'~~> Increase last row by 1 for output
zLastRow = zLastRow + 1
Else
Exit Do
End If
Loop
Else
MsgBox Collection & " not Found"
End If
End With
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub

I think it would be simpler to use the AdvancedFilter method, but your data setup is important.
I have assumed that your original data has Five columns (A:E), with headers being in Row 1
I have further assumed that the headers in columns A:C are "Collection", "System" and "Tag"
I have also assumed there is nothing of importance on "Test" (If there is, instead of "clearing" the entire worksheet, you can alter the code to only clear the relevant part, perhaps the first four columns.
Set up a criteria range (three columns, two rows) on your Imported Data sheet with the same headings in Row 1 as in columns A:C of your data source. You could use Data Validation to force an entry; or you could code something within the macro itself. Or you could develop a UserForm to populate these cells
After your user fills in the criteria, the macro should copy the relevant data. If all three items are populated, it will delete column D, otherwise, it will delete columns D:E.
If I've made some wrong assumptions about how your data is set up, you may need to delete more columns after doing the Filter.
Option Explicit
Sub FilterButton()
Dim SrcSheet As Worksheet, DestSheet As Worksheet
Dim SourceRange As Range
Dim CriteriaRange As Range
Dim DestRange As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
'~~> Set your sheet
Set DestSheet = Sheets("Test")
Set SrcSheet = Sheets("Imported Data")
'~~> Set your ranges
Set SourceRange = SrcSheet.Range("a1").CurrentRegion
Set CriteriaRange = SrcSheet.Range("H1:J2") 'or wherever
Set DestRange = DestSheet.Range("A1")
'Activate Destination Sheet, Clear it, and run the filter
DestSheet.Activate 'Can only copy filtered data to active sheet
DestSheet.Cells.Clear
SourceRange.AdvancedFilter xlFilterCopy, CriteriaRange, DestRange
'Delete column D always, delete Column E if not three criteria
With DestRange.CurrentRegion
If WorksheetFunction.CountA(CriteriaRange.Rows(2)) <> 3 Then
Range(.Columns(4), .Columns(5)).Delete
Else
.Columns(4).Delete (xlToLeft)
End If
End With
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub

Related

Is there an efficient way to update data from one sheet to another with a match of a cell

I have a sheet that has a main tab and a data tab. I update the data tab daily by copying from a daily report I get automatically from a reporting portal. I dump that data into the data tab and have written some code to update some of the columns in the main tab. The code matches the loan number in column C, if a match is found it executes the copy and paste.
The code works perfectly but it is slow as I've added other columns to copy.
I am asking the experts to review my code and maybe show me a more efficient way of writing the code so it can run faster. The data it is searching through is only a couple of hundred rows, I don't think it should take too long.
Here is my code:
Sub Update_Data()
ActiveSheet.Unprotect Password:="Mortgage1"
Application.ScreenUpdating = False
Dim stNow As Date
Dim sourceRng As Range
Dim destRng As Range
stNow = Now
lrowloans = Worksheets("Main").Range("A6").End(xlDown).Row
lrowdata = Worksheets("Data").Range("C11").End(xlDown).Row
Set sourceRng = Worksheets("Main").Range("A6:A" & lrowloans)
Set destRng = Worksheets("Data").Range("C11:C" & lrowdata)
Dim match As Boolean
For Each sRng In sourceRng
If sRng.Value <> "" Then
With destRng
Set dRng = .Find(What:=sRng.Value, After:=Worksheets("Data").Range("C11"), LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
If Not dRng Is Nothing Then
Set pasteRng = Worksheets("Main").Range("E" & sRng.Row)
Set copyRng = Worksheets("Data").Range("G" & dRng.Row & ":H" & dRng.Row)
copyRng.Copy pasteRng
Set pasteRng = Worksheets("Main").Range("B" & sRng.Row)
Set copyRng = Worksheets("Data").Range("D" & dRng.Row & ":E" & dRng.Row)
copyRng.Copy pasteRng
Set pasteRng = Worksheets("Main").Range("D" & sRng.Row)
Set copyRng = Worksheets("Data").Range("U" & dRng.Row & ":U" & dRng.Row)
copyRng.Copy pasteRng
Set pasteRng = Worksheets("Main").Range("M" & sRng.Row)
Set copyRng = Worksheets("Data").Range("Q" & dRng.Row & ":Q" & dRng.Row)
copyRng.Copy pasteRng
Set pasteRng = Worksheets("Main").Range("K" & sRng.Row)
Set copyRng = Worksheets("Data").Range("AP" & dRng.Row & ":AP" & dRng.Row)
copyRng.Copy pasteRng
Set pasteRng = Worksheets("Main").Range("N" & sRng.Row)
Set copyRng = Worksheets("Data").Range("AW" & dRng.Row & ":AW" & dRng.Row)
copyRng.Copy pasteRng
End If
End With
End If
Next
Application.ScreenUpdating = True
ActiveSheet.Protect Password:="Mortgage1"
End Sub
This will run just about as fast as your computer can do the job. Any difference is achieved by reading from the sheets less frequently. I didn't find any significant sources for delay in your code, such as avoidable loops.
Option Explicit
' the assigned numbers are Excel's column numbers
' Test: Debug.Print Columns(NmcName).Address(0,0)
Enum Ndc ' "Data" columns enumeration
' 132 - 08 Dec 2020
NdcName = 4 ' 4 = column D
NdcProc ' "Processor"
NdcPurp = 7 ' "Purpose"
NdcProd ' "Product type"
NdcLockX = 17 ' "Lock Expiry"
NdcLoan = 21 ' "Loan amount"
NdcCD = 42 ' "CD issued"
NdcClose = 49 ' "Closing date"
End Enum
Enum Nmc ' "Main" columns
' 132 - 08 Dec 2020
NmcName = 2 ' 2 = column B
NmcProc ' "Processor"
NmcLoan ' "Loan amount"
NmcPurp ' "Purpose"
NmcProd ' "Product type"
NmcCD = 11 ' "CD issued"
NmcLockX = 13 ' "Lock Expiry"
NmcClose ' "Closing date"
End Enum
Sub Update_Data()
' 132 - 08 Dec 2020
Const pWord As String = "Mortgage1"
Dim WsMain As Worksheet
Dim WsData As Worksheet
Dim sourceRng As Range
Dim destRng As Range
Dim sCell As Range ' loop object
Dim Fnd As Range ' cell found by Find
Dim SrcArr As Variant ' data from Fnd.Row
Dim SrcClm As Variant ' array of source columns
Dim DstClm As Variant ' array of destination columns
Dim C As Long ' loop counter: column
Set WsMain = Worksheets("Main")
Set WsData = Worksheets("Data")
With WsMain
.Unprotect Password:=pWord ' presuming WsMain is your AciveSheet
Set sourceRng = .Range(.Cells(6, "A"), .Cells(.Rows.Count, "A").End(xlUp))
End With
With WsData
Set destRng = .Range(.Cells(11, "C"), .Cells(.Rows.Count, "C").End(xlUp))
End With
' data will be copied from SrcClm to DstClm, like NdcPurp to NmcPurp
' sequence is immaterial but position must match
' number of columns in both arrays must be identical
' effect modifications in the Enum
SrcClm = Array(NdcPurp, NdcProd, NdcName, NdcProc, NdcLoan, NdcLockX, NdcCD, NdcClose)
DstClm = Array(NmcPurp, NmcProd, NmcName, NmcProc, NmcLoan, NmcLockX, NmcCD, NmcClose)
Application.ScreenUpdating = False
For Each sCell In sourceRng
If sCell.Value <> "" Then
With destRng
Set Fnd = .Find(What:=sCell.Value, _
After:=.Cells(1), _
LookIn:=xlValues, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False, _
SearchFormat:=False)
If Not Fnd Is Nothing Then
SrcArr = .Range(.Cells(Fnd.Row, 1), .Cells(Fnd.Row, NdcClose)).Value
For C = LBound(SrcClm) To UBound(SrcClm)
WsMain.Cells(sCell.Row, DstClm(C)).Value = SrcArr(1, SrcClm(C))
Next C
End If
End With
End If
Next sCell
With Application
.CutCopyMode = False
.ScreenUpdating = True
End With
WsMain.Protect Password:=pWord
End Sub
The code's syntax has been tested but, for lack of data, not its functionality. Especially the coordination of enumerations Ndc and Nmc with the arrays SrcClm and DstClm may write some values to the wrong columns. Here's how you can fix that. Look for these two arrays.
SrcClm = Array(NdcPurp, NdcProd, NdcName, NdcProc, NdcLoan, NdcLockX, NdcCD, NdcClose)
DstClm = Array(NmcPurp, NmcProd, NmcName, NmcProc, NmcLoan, NmcLockX, NmcCD, NmcClose)
SrcClm lists all used columns in the source sheet. DstClm lists all used columns in the destination sheet. You can add, delete or change either. The sequence is immaterial. But for every Source cell there must be a destination cell. Therefore the number of columns in both arrays must always be the same.
The arrays specify columns. The rows will be found by the code. The Source row is determined one after the other, in a loop. The Destination row is Fnd.Row. Now the code works through the two arrays. It takes the first column from SrcClm, finds the cell with the help of the provided row and pastes it to the first column from the DstClm array in the Fnd.Row row.
Example:- The first SrcClm is NdcG which was given a value of 7 (column G) in the enumeration. The first DstClmis NmcE which has a value of 5 (column E) in the enumeration. Now, presume instead of reading from column G you wanted to read from column H. So you start from the Enumeration. Change the assigned value from 7 to 8. Note that this change would automatically also change the value of NdcH. This is because NdcH as no value assigned to it which VBA understands to mean "next number". So, when you change NdcG to , NdcH will become 9 and you may have to change that, too.
After you change the value of NdcG the code will read from column H, just as you wanted, but the enumeration's name is wrong. Had we given descriptive names to the enumerations, like NdcName, NdcDob and NdcContractID this problem wouldn't exist. But as it is now NdcG must be changed to NdcH and you can't do that before you change the existing NdcH to NdcI.
Anyway, don't change the name in the enumeration. Instead, use Edit > Replace and replace all occurrences of NdcH with NdcI and, thereafter, all occurrences of NdcG to NdcH. All of this sounds complicated and it is that. You need to give your full attention to avoid mistakes.
Of course, in this way you can change any source or destination column in the system. It's not difficult and can be completed quite fast after you have done it once.

Copy row of data based on criteria AND "label" that copied data in last column

I have working code that checks for a criteria in each row, and if met, copies that whole row of data over to a different workbook. But! I need to be able to add text to the last column of the copied data (Column S) that essentially labels what criteria was met that made the code copy it over because I will soon be expanding to check for multiple different criteria.
So for every row that meets the criteria and gets copied, I want to add "Criteria1" next to it in column S in the new workbook (it will always be column S that will be the first available column).
I have mangled this code together through inheritance and all of your help, so I don't really even know where to begin.
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
Dim CoderBook As Workbook
Dim Referrals As Worksheet
Dim Review As Workbook
Dim Crit As Worksheet
Dim LastRow As Long
Dim NextRow As Long
Dim i As Long
Set CoderBook = Workbooks.Open("Coder Referrals.xlsx")
Set Referrals = CoderBook.Sheets("Sheet1")
Set Review = ThisWorkbook
Set Crit = Review.Sheets("Criteria")
'Search code
LastRow = Crit.Cells.Find(What:="*", After:=[A1], SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Application.ScreenUpdating = False
'Loop search code
For i = 2 To LastRow
'Specialized Criteria1 Check
If Crit.Range("F" & i) <> Crit.Range("G" & i) Or _
Crit.Range("I" & i) <> Crit.Range("J" & i) Then
'If meets Criteria1 check, then copy appropriate rows to CoderBook Referrals sheet
Referrals.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).EntireRow.Value = Crit.Rows(i).Value
End If
Next i
'End loop code
CoderBook.Close SaveChanges:=True
Application.ScreenUpdating = True
End Sub
Split the or into two statements:
For i = 2 To LastRow
j = Referrals.Cells(Rows.Count, 1).End(xlUp).row + 1
'Specialized Criteria1 Check
If Crit.Range("F" & i) <> Crit.Range("G" & i) Then
'If meets Criteria1 check, then copy appropriate rows to CoderBook Referrals sheet
Referrals.Rows(j).EntireRow.Value = Crit.Rows(i).Value
Referrals.Range("S" & j).Value = "Criteria1"
End If
If Crit.Range("I" & i) <> Crit.Range("J" & i) Then
Referrals.Rows(j).EntireRow.Value = Crit.Rows(i).Value
if Referrals.Range("S" & j).value = vbNullString then
Referrals.Range("S" & j).Value = "Criteria2"
Else
Referrals.Range("S" & j).Value = Referrals.Range("S" & j).Value & ", " & "Criteria2"
End if
Next i

Excel VBA mark duplicate on colA (work on all worksheet include activesheet)

I'd like to mark duplicate on all Worksheet in Workbook. Below the code mark only duplicate if the duplicate exist on other worksheet.
I'd like to mark them also if them exist on Activesheet.
(much better if it possible to mark on different color if duplicate exist only in Activesheet)
Here's a link for solution on similar case, What I need to solve. [a link](https://stackoverflow.com/a/25252503/5493335) "loops through the values of Col A in the sheet which gets activated and then it searches the Col A of all the remaining worksheets and if it finds the ID then it colors the cell background to red. by Siddhart Rout"
I add only one change to this code to eliminate color on empty rows.
But those code is mark(on red color) only if duplicate is one another Worksheet.
I wonder to makr on diffrent color if I found duplicate on activeworksheet.
I will trying to do myself and change the condition with else but It doesn't work. Could anybody get me some help to solve that issue.
Thanks in advance.
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Dim lRow As Long, wsLRow As Long, i As Long
Dim aCell As Range
Dim ws As Worksheet
Dim strSearch As String
With Sh
'~~> Get last row in Col A of the sheet
'~~> which got activated
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Remove existing Color from the column
'~~> This is to cater for any deletions in the
'~~> other sheets so that cells can be re-colored
.Columns(1).Interior.ColorIndex = xlNone
'~~> Loop through the cells of the sheet which
'~~> got activated
For i = 1 To lRow
'~~> Store the ID in a variable
strSearch = .Range("A" & i).Value
if strSearch <> "" then 'eliminated color empty cell
'~~> loop through the worksheets in the workbook
For Each ws In ThisWorkbook.Worksheets
'~~> This is to ensure that it doesn't
'~~> search itself
If ws.Name <> Sh.Name Then
'~~> Get last row in Col A of the sheet
wsLRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
'~~> Use .Find to quick check for the duplicate
Set aCell = ws.Range("A1:A" & wsLRow).Find(What:=strSearch, _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False, _
SearchFormat:=False)
'~~> If found then color the cell red and exit the loop
'~~> No point searching rest of the sheets
If Not aCell Is Nothing Then
Sh.Range("A" & i).Interior.ColorIndex = 3
Exit For
End If
End If
Next ws
End if
Next i
End With
End Sub
I'd go with the following refactoring of your code:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Dim IDsRng As Range, IDCell As Range
Dim ws As Worksheet
Dim strSearch As String
Dim foundInOtherSheet As Boolean, foundInActiveSheet As Boolean
With Sh
Set IDsRng = .Range("A1", .Cells(.Rows.count, 1).End(xlUp)) '<--| set the IDs range as all column A not empty cells with some "text" content
'~~> Remove existing Color from the column
'~~> This is to cater for any deletions in the other sheets so that cells can be re-colored
.Columns(1).Interior.ColorIndex = xlNone
End With
For Each IDCell In IDsRng '<--| Loop through ID cells (i.e. column A "text" cells of the activated sheet)
'~~> Store the ID in a variable
strSearch = IDCell.Value
foundInActiveSheet = WorksheetFunction.CountIf(IDsRng, strSearch) > 1 '<--| count possible dupes in active sheet
foundInOtherSheet = False '<--| initialize it at every new ID
'~~> loop through the worksheets in the workbook
For Each ws In ThisWorkbook.Worksheets
'~~> This is to ensure that it doesn't search itself
If ws.Name <> Sh.Name Then
With ws
foundInOtherSheet = WorksheetFunction.CountIf(.Range("A1", .Cells(.Rows.count, 1).End(xlUp)), strSearch) > 1
If foundInOtherSheet Then Exit For '~~> If found then color then no point searching rest of the sheets
End With
End If
Next
Select Case True '<--| now act accordingly to where duplicates have been found
Case foundInOtherSheet And Not foundInActiveSheet '<--| if duplicates found in "other" sheets only
IDCell.Interior.ColorIndex = 3 '<--| red
Case foundInOtherSheet And foundInActiveSheet '<--| if duplicates found in "other" sheets and in "active" one too
IDCell.Interior.ColorIndex = 6 '<--| yellow
Case Not foundInOtherSheet And foundInActiveSheet '<--| if duplicates found in "active" sheets only
IDCell.Interior.ColorIndex = 14 '<--| green
End Select
Next
End Sub
remove the If ws.Name <> Sh.Name Then line and end if underneath in line with it.

Extract matched data from a table to another worksheet in Excel VBA

I've got a sample table in Sheet1 as below:
Location Model Part #
BF03 200W 40536573
BF04 200W 40536573
CV01 120W 40536585
CV02 135W 20085112
CV03 900W 20349280
CV04 135W 20085112
As a reference data of BF03 is in cell B6.
What I need it to do is:
A) When user typed part number (ex: 40536573) in Sheet3 say cell A1, only the matched location will be picked up
B) The picked up "location" value will be tabulated in Sheet2 starting from cell A6.
The output will look something like this:
Location Model Part #
BF03 200W 40536573
BF04 200W 40536573
To make matter more complicated, I would then need to have the "Location" data to be concatenated into a string and store it in Sheet 2 Cell A2.
I'm guessing we need to do a For Loop count rows but I couldn't get any reference on how to write it properly.
Below are what my error "OVERFLOW" code looks like
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim FindMatch As String
Dim Rng As Range
Dim counter As Integer
counter = ActiveWorkbook.Worksheets("Sheet2").Range("A6", Worksheets("Sheet2").Range("A6").End(xlDown)).Rows.Count
For i = 6 To counter
'Get the value from other sheet set as FindMatch
FindMatch = Sheets("Sheet3").Cell("A1").Value
'Find each row if matches the desired FindMatch
If Trim(FindMatch) <> "" Then
With Sheets("Sheet2").Range("D" & i).Rows.Count
Set Rng = .Find(What:=FindMatch, _
after:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
'copy the values required to the cell
Cells(i, 2) = Sheets("Sheet2").Cells(Rng.Row, 2)
Else
MsgBox "Nothing found"
End If
End With
End If
Next i
End Sub
Instead of using the .find method, I managed to use a simple for loop. Sometimes you need to think simple i guess :) I have also added a small function to clear previously used fields. If you check and give feedback if you face any problem, we can try to fix it.
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Dim S_Var As String
Dim copyRange As Range
Dim ws1_lastrow As Long
Dim ws2_lastrow As Long
Dim searchresult As Range
Set ws1 = Sheets("Sheet1")
Set ws2 = Sheets("Sheet2")
Set ws3 = Sheets("Sheet3")
S_Var = ws3.Range("A1").Value
ws1_lastrow = ws1.Range("A" & ws1.Rows.Count).End(xlUp).Row
Set copyRange = ws1.Range("A1:C" & ws1_lastrow)
'Clear Data
ws2.Range("A2").Value = ""
If Range("A7").Value <> "" Then
ws2.Range("A7:C" & ws2.Range("A" & ws1.Rows.Count).End(xlUp).Row).Value = ""
End If
'Searchin through the sheet1 column1
For i = 2 To ws1_lastrow
If ws1.Range("C" & i) = S_Var Then
ws2_lastrow = ws2.Range("A" & ws2.Rows.Count).End(xlUp).Row
ws1.Range("A" & i & ":C" & i).Copy Destination:=ws2.Range("A" & ws2_lastrow + 1)
End If
Next
'Adding location to sheet2 A2 as string
ws2_lastrow = ws2.Range("A" & ws1.Rows.Count).End(xlUp).Row
For i = 7 To ws2_lastrow 'starting from 7, where location starts
If ws2.Range("A2").Value = "" Then
ws2.Range("A2").Value = ws2.Range("A" & i).Value
Else
ws2.Range("A2").Value = ws2.Range("A2").Value & "," & ws2.Range("A" & i).Value
End If
Next

Defining a range from values in another range

I have an excel file of tasks which have either been completed or not, indicated by a Yes or No in a column. Ultimately I am interested in data in a different column but I want to set up the code so it ignores those rows where the task has been completed. So far I have defined the column range containing the yes/no's but I don't know which command to run on this range. I imagine I want to define a new range based on the value in column C.
Option Explicit
Sub Notify()
Dim Chk As Range
Dim ChkLRow As Long
Dim WS1 As Worksheet
On Error GoTo WhatWentWrong
Application.ScreenUpdating = False
'--> If the text in column C is Yes then Ignore (CountIF ?)
'--> Find last cell in the column, set column C range as "Chk"
Set WS1 = Sheets("2011")
With WS1
ChkLRow = .Range("C" & Rows.Count).End(xlUp).Row
Set Chk = .Range("C1:C" & ChkLRow)
End With
'--> Else Check date in column H
'--> Count days from that date until today
'--> Display list in Message Box
Reenter:
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Exit Sub
WhatWentWrong:
MsgBox Err.Description
Resume Reenter
Application.ScreenUpdating = True
End Sub
Would it perhaps be easier to simply define one range based on the values in column C rather than first defining column C as the range and then redefining it?
Thanks
Yes Column H has the date the task 'arrived' and I want to display a count from then to the current date. The tasks are identified by a 4 digit code in Column A. I envisage the message box saying Task '1234' outstanding for xx days. – Alistair Weir 1 min ago
Is this what you are trying? Added Col I for visualization purpose. It holds no significance otherwise.
Option Explicit
Sub Notify()
Dim WS1 As Worksheet
Dim Chk As Range, FltrdRange As Range, aCell As Range
Dim ChkLRow As Long
Dim msg As String
On Error GoTo WhatWentWrong
Application.ScreenUpdating = False
Set WS1 = Sheets("2011")
With WS1
ChkLRow = .Range("C" & Rows.Count).End(xlUp).Row
'~~> Set your relevant range here
Set Chk = .Range("A1:H" & ChkLRow)
'~~> Remove any filters
ActiveSheet.AutoFilterMode = False
With Chk
'~~> Filter,
.AutoFilter Field:=3, Criteria1:="NO"
'~~> Offset(to exclude headers)
Set FltrdRange = .Offset(1, 0).SpecialCells(xlCellTypeVisible)
'~~> Remove any filters
ActiveSheet.AutoFilterMode = False
For Each aCell In FltrdRange
If aCell.Column = 8 And _
Len(Trim(.Range("A" & aCell.Row).Value)) <> 0 And _
Len(Trim(aCell.Value)) <> 0 Then
msg = msg & vbNewLine & _
"Task " & .Range("A" & aCell.Row).Value & _
" outstanding for " & _
DateDiff("d", aCell.Value, Date) & "days."
End If
Next
End With
End With
'~~> Show message
MsgBox msg
Reenter:
Application.ScreenUpdating = True
Exit Sub
WhatWentWrong:
MsgBox Err.Description
Resume Reenter
End Sub
SNAPSHOT
Why not brute force it.
Dim r_table as Range, i as Integer, N as Integer
' Start from the top
Set r_table = Sheets("2011").Range("C1")
' Find the last entry on column C and count the # of cells
N = Sheets("2011").Range(r_table, r_table.End(xlDown)).Rows.Count
Dim table_values() as Variant
' This will transfer all the values from the spreadsheet into an VBA array
' and it works super fast. Access values with A(row,col) notation.
table_values = r_table.Resize(N, 5).Value2 ' No. of columns is 5 ?
For i=1 to N
If table_values(i,1)="Yes" Then 'Check Column C
Else
... table_values(i,5) ' Column H
End if
Next i
MsgBox ....
This will be super fast, with no flicker on the screen.

Resources