VBA function not doing anything [duplicate] - excel

This question already has answers here:
UDF using FindNext seems to abort without warning
(1 answer)
Why does my spreadsheet function behave differently than when called from code?
(2 answers)
Closed 1 year ago.
I am writing script/code/something to loop through each worksheet in the workbook and it is supposed to get the values from the worksheets that match the criteria. But when I run the function I do not get any value and when I have added MsgBox to see how far the code has gone it doesn't trigger.
I want the code to cycle through each worksheet and then gather the data as coded.
Anyone know what I am doing wrong?
(Also I am new to Stackoverflow so if I need to improve my post in anyway please let me now!)
Function FindBelopp(Month As String, Typ As String) As Double
Dim rng As Range
Dim beloppColumn As Range
Dim lRow As Range
Dim firstAddress As Range
Dim ws As Worksheet
Dim rngAmount As Double
Dim ws_Count As Integer
Dim I As Integer
I = 1
ws_Count = Worksheets.Count
Do While I < ws_Count
Set ws = Worksheets(I)
If InStr(1, ws.Name, Month, 0) > 0 Then
With ws.Cells
Set beloppColumn = .Find("SEK", LookIn:=xlValues)
Set rng = .Find(Typ, LookIn:=xlValues, lookAt:=xlWhole)
If Not rng Is Nothing Then
Set firstAddress = rng
Do
If IsEmpty(rng.Offset(1, 0)) = True Then
Set lRow = Range(Cells(rng.Row, beloppColumn.Column), Cells(rng.End(xlDown)(0).Row, beloppColumn.Column))
Else
Set lRow = Range(Cells(rng.Row, beloppColumn.Column), Cells(rng.Row, beloppColumn.Column))
End If
If Application.Sum(lRow) > 0 Then
rngAmount = Application.Sum(lRow) + rngAmount
Else: End If
Set rng = .FindNext(rng)
Loop While rng.Address <> firstAddress.Address
Else: End If
End With
Else: End If
I = I + 1
Loop
FindBelopp = rngAmount
End Function
First of all.
Thank you for the quick response and for teaching me something new.
The issue was with .FindNext()
I made it work in a similar fashion and it might not be the most efficient use but incase of someone stumbling here with the same issue I thought I could add my now working code.
Function LoopThroughEachSheet(iWantMonths As String, iWantValues As String) As Double
Dim rng As Range
Dim firstAddress As Range
Dim moneyColumn As Range
Dim sumRows As Range
Dim lRow As Range
Dim Money As Double
Dim ws As Worksheet
For Each ws In Worksheets
If InStr(1, _
UCase(ws.Name), _
UCase(iWantMonths)) > 0 Then
With ws.Cells
Set rng = .Find(iWantValues, _
lookAt:=xlWhole, _
LookIn:=xlValues)
If Not rng Is Nothing Then
Set firstAddress = rng
Set moneyColumn = .Find("SEK", _
LookIn:=xlValues, _
lookAt:=xlWhole)
Do
With ws
Set lRow = rng.End(xlDown)(0)
If IsEmpty(rng.Offset(1, 0)) = True Then
Set sumRows = .Range(Cells(rng.Row, moneyColumn.Column).Address, _
Cells(lRow.Row, moneyColumn.Column).Address)
Else
Set sumRows = .Cells(rng.Row, moneyColumn.Column)
End If
End With
Money = Application.Sum(sumRows) + Money
Set rng = .Find(iWantValues, _
After:=rng, _
lookAt:=xlWhole, _
LookIn:=xlValues)
Loop While firstAddress.Address <> rng.Address
Else: End If
End With
Else: End If
Next
LoopThroughEachSheet = Money
End Function

Related

i want to find and hightlight a specific word in a excel, but the whole cell is getting highlighted pls help me

Sub Sample()
Dim fnd As String
Dim MyAr
Dim i As Long
Dim rng As Range, FoundCell As Range, LastCell As Range, myRange As Range
Set myRange = ActiveSheet.UsedRange
Set LastCell = myRange.Cells(myRange.Cells.Count)
fnd = "university/checklist"
MyAr = Split(fnd, "/")
For i = LBound(MyAr) To UBound(MyAr)
Set FoundCell = myRange.Find(what:=MyAr(i), after:=LastCell)
If Not FoundCell Is Nothing Then
FirstFound = FoundCell.Address
End If
Set rng = FoundCell
Do Until FoundCell Is Nothing
Set FoundCell = myRange.FindNext(after:=FoundCell)
Set rng = Union(rng, FoundCell)
If FoundCell.Address = FirstFound Then Exit Do
Loop
If Not rng Is Nothing Then
rng.Characters.Font.ColorIndex = 3
End If
Next i
End Sub
Highlight Strings in Cells
Option Explicit
Sub HighlightStrings()
Const CriteriaList As String = "university,checklist"
Const CriteriaColor As Long = vbRed
Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
Dim rg As Range: Set rg = ws.UsedRange
Dim Criteria() As String: Criteria = Split(CriteriaList, ",")
Dim c As Long
Dim cLen As Long
Dim cString As String
Dim fCell As Range
Dim fArr() As String
Dim f As Long
Dim fPos As Long
Dim fString As String
Dim fFirstAddress As String
For c = 0 To UBound(Criteria)
cString = Criteria(c)
cLen = Len(cString)
Set fCell = rg.Find(cString, , xlFormulas, xlPart)
If Not fCell Is Nothing Then
fFirstAddress = fCell.Address
Do
fString = fCell.Value
fPos = 1
fArr = Split(fString, cString, , vbTextCompare)
For f = 0 To UBound(fArr) - 1
fPos = fPos + Len(fArr(f))
fCell.Characters(fPos, cLen).Font.Color = CriteriaColor
fPos = fPos + cLen
Next f
Set fCell = rg.FindNext(fCell)
Loop Until fCell.Address = fFirstAddress
End If
Next c
MsgBox "Criteria strings highlighted.", vbInformation
End Sub
Please, try the next updated code. As I said in my above comment you cannot use a Union range for what you try doing, because you need to search for each cell and find the appropriate cell characters to be colored. You can iterate between such a range again but nothing will be gain:
Dim fnd As String, FirstFound As String, MyAr, i As Long, pos As Long
Dim FoundCell As Range, LastCell As Range, myRange As Range
Set myRange = ActiveSheet.UsedRange
Set LastCell = myRange.cells(myRange.cells.count)
fnd = "university/checklist"
MyAr = Split(fnd, "/")
For i = LBound(MyAr) To UBound(MyAr)
Set FoundCell = myRange.Find(MyAr(i)), , , xlPart
If Not FoundCell Is Nothing Then
FirstFound = FoundCell.Address
pos = InStr(1, FoundCell.Value, MyAr(i), vbTextCompare)
FoundCell.Characters(pos, Len(MyAr(i))).Font.ColorIndex = 3
Do
Set FoundCell = myRange.FindNext(FoundCell)
pos = InStr(1, FoundCell.Value, MyAr(i))
FoundCell.Characters(pos, Len(MyAr(i))).Font.ColorIndex = 3
Loop While FoundCell.Address <> FirstFound
End If
Next i
End Sub
If the range to be processed is large, you should use some optimization lines as Application.ScreenUpdating = False, Application.EnableEvents = False and
Application.Calculation = xlManual at the beginning of the code and ending with Application.ScreenUpdating = False, Application.EnableEvents = False and
Application.Calculation = xlCalculationAutomatic
First of, try to tidy a bit your code example, it's quite messy hence I am not sure of what you are actually trying to achieve. Some accompanying comments would help also
Anyway, one thing is for sure :
rng.Characters.Font.ColorIndex = 3
will attribute a color to the whole text in the selected range. To specify only a subset of the text in the range, you need to use :
rng.Characters(Start:=x, Length:=y).Font.ColorIndex = 3
Where x being the starting character and Length being the length that you want to turn into the given font color.
You can find the start value and length using
start = InStr(1, rng, MyAr(i))
length = len(MyAr(i))
Which will lead to the following line
rng.Characters(Start:=start, Length:=length).Font.ColorIndex = 3
And as specified by FaneDuru, it should be done on a cell by cell basis. Either you do it instead of the Union, or you look on the cells within the rng.
for cell in rng.Cells
start = InStr(1, cell, MyAr(i))
...
next cell
Moreover, as described here, it will only color the first occurrence.
If the value you are looking for can appear several time, you either need an alternate way or set some iteration until there are no more matches by modifying the starting position in the InStr where 1 would become the last matched position + 1

FindNext property of Range Object cannot be assigned

I have written a code, which includes the FindNext method. All the code works so far, only when it gets to the FindNext method it shows an error saying the FindNext Object cannot be assigned.
However, I don't see where the Range Object (in this case "cell") is changed in any way for the FindNext method to not be able to assign it. Has anybody got an idea?
Please ignore any chunky written code, I'm very new with VBA ;)
Sub Search()
Dim wks As Worksheet
Set wks = ActiveSheet
Dim cell As Range, sngCell As Range
Dim Count As Long
Dim firstCell As String
Dim rg As Range, lastColumn As Long
Set cell = wks.Cells.Find(what:="Planned Supply at BP|SL (EA)", LookIn:=xlValues, lookat:=xlWhole)
firstCell = cell.Address
Do
With wks
lastColumn = .Cells(cell.Row, .Columns.Count).End(xlToLeft).Column
Set rg = Range(cell, .Cells(cell.Row, lastColumn))
End With
For Each sngCell In rg
If IsNumeric(sngCell.Value) = True Then
If sngCell.Value > 0 Then
If sngCell.Offset(-2, 0).Value > sngCell.Value Then
Count = Count + 1
End If
If Count = 0 Then
Rows(sngCell.Row - 2).Delete
Rows(sngCell.Row - 1).Delete
Rows(sngCell.Row).Delete
End If
End If
End If
Next
Set cell = wks.Cells.FindNext(cell)
Loop While cell.Address <> firstCell
End Sub
Find() in a loop is complex enough that it's worth splitting it out into a separate function. Here's a slightly different approach which reduces the complexity in your main Sub and allows you to focus on the business rules instead of the nuances of using Find()
Sub Search()
Dim wks As Worksheet
Dim cell As Range, sngCell As Range
Dim firstCell As String
Dim rg As Range, lastColumn As Long, matches As Collection
Set wks = ActiveSheet
Set matches = FindAll(wks.Cells, "Planned Supply at BP|SL (EA)")
For Each cell In matches
Debug.Print "Found:", cell.Address
Set rg = wks.Range(cell, wks.Cells(cell.Row, Columns.Count).End(xlToLeft))
For Each sngCell In rg.Cells
If IsNumeric(sngCell.Value) Then 'no need for `= True`
If sngCell.Value > 0 Then
If sngCell.Offset(-2, 0).Value <= sngCell.Value Then
sngCell.Offset(-2, 0).Resize(3).EntireRow.Delete
Exit For 'stop checking...
End If
End If
End If
Next
Next cell
End Sub
'Find all matches for `val` in `rng` and return as a collection
Public Function FindAll(rng As Range, val As String) As Collection
Dim rv As New Collection, f As Range, addr As String
Set f = rng.Find(what:=val, after:=rng.Cells(rng.Cells.CountLarge), _
LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False)
If Not f Is Nothing Then addr = f.Address()
Do Until f Is Nothing
rv.Add f
Set f = rng.FindNext(after:=f)
If f.Address() = addr Then Exit Do
Loop
Set FindAll = rv
End Function

How would I loop this Function over column Q with VBA?

I have the following code and it does what I want it to as far as removing the data I want to remove. The only thing is I have to run it over and over and over for it to get through all of the data. How would I get this to loop over just column q?
Sub SdeleteDeclinesfoReal()
Dim sString As String
Dim MyAr
Dim i As Long
Dim delRange As Range, aCell As Range
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
'~~> Add more to the list here separated by "/"
sString = "Declined/Self ACH"
MyAr = Split(sString, "/")
With ws
For i = LBound(MyAr) To UBound(MyAr)
Set aCell = .Columns(17).Find(What:=MyAr(i), LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase :=False, SearchFormat:=False)
If Not aCell Is Nothing Then
If delRange Is Nothing Then
Set delRange = .Rows(aCell.Row)
Else
Set delRange = Union(delRange, .Rows(aCell.Row))
End If
End If
Next i
End With
'...
End Sub
Loop Through Column
A Find Method Solution
Option Explicit
Sub SdeleteDeclinesfoReal()
Const FirstRow As Long = 2
Const CritCol As String = "Q"
Dim Criteria As Variant
'~~> Add more to the list here
Criteria = Array("Declined", "Self ACH")
Dim ws As Worksheet
Dim rng As Range, delRange As Range, aCell As Range
Dim i As Long
Dim sString As String
Dim FirstAddress As String
Set ws = ThisWorkbook.Sheets("Sheet1")
' Define range "Q2:Q1048576" (FirstRow, CritCol).
Set rng = ws.Cells(FirstRow, CritCol).Resize(ws.Rows.Count - FirstRow + 1)
' Define last non-blank cell.
Set rng = rng.Find(What:="*", _
LookIn:=xlValues, _
SearchDirection:=xlPrevious)
If Not rng Is Nothing Then
' Define 'non-blank' range.
Set rng = ws.Cells(FirstRow, CritCol).Resize(rng.Row - FirstRow + 1)
With rng
For i = LBound(Criteria) To UBound(Criteria)
sString = Criteria(i)
Set aCell = .Find(What:=sString, _
LookAt:=xlWhole)
If Not aCell Is Nothing Then
FirstAddress = aCell.Address
Do
If delRange Is Nothing Then
Set delRange = aCell.EntireRow
Else
Set delRange = Union(delRange, aCell.EntireRow)
End If
Set aCell = .FindNext(aCell)
' Prevent infinite loop caused by the 'FindNext' method.
Loop Until aCell.Address = FirstAddress
Else
' Criteria not found.
End If
' Prevent infinite loop when a criteria is found and one
' of the next is not.
Set aCell = Nothing
Next i
End With
If Not delRange Is Nothing Then
delRange.Select ' Test with 'Select'. Later change to 'Delete'.
Else
' Nothing cell found.
End If
Else
' All cells below first row are blank (empty or "").
End If
End Sub
A Reminder Why to Use Union
Copy the examples into a standard module, e.g. Module1 of a new workbook.
The first two procedures show how to increase efficiency using an array, but are primarily here to better understand what the last three procedures do.
Run the trio each after populating the values, and monitor how long they take and look at the ActiveSheet before and after to see the differences.
Test Union
Option Explicit
' Slow
Sub populateValuesSlow()
Const NoR As Long = 5000
Const NoC As Long = 10
Dim i As Long
Dim j As Long
For i = 1 To NoR
For j = 1 To NoC
Cells(i, j) = Int(Rnd() * (10 - 1)) + 1
Next j
Next i
End Sub
' Fast
Sub populateValuesFast()
Const NoR As Long = 5000
Const NoC As Long = 10
Dim i As Long
Dim j As Long
Dim Data As Variant
ReDim Data(1 To NoR, 1 To NoC)
For i = 1 To NoR
For j = 1 To NoC
Data(i, j) = Int(Rnd() * (10 - 1)) + 1
Next j
Next i
Cells(1, 1).Resize(UBound(Data, 1), UBound(Data, 2)).Value = Data
End Sub
' Wrong: in this case, half of the data still remains.
Sub deleteRowsOneRowAtTheTimeWrong()
Const NoR As Long = 5000
Dim i As Long
For i = 1 To NoR
Rows(i).Delete
Next i
End Sub
' Right but Slow
Sub deleteRowsOneRowAtTheTime()
Const NoR As Long = 5000
Dim i As Long
For i = NoR To 1 Step -1
Rows(i).Delete
Next i
End Sub
' Right and Fast
Sub deleteRowsWithUnion()
Const NoR As Long = 5000
Dim rng As Range
Dim i As Long
For i = 1 To NoR
If Not rng Is Nothing Then
Set rng = Union(rng, Rows(i))
Else
Set rng = Rows(i)
End If
Next i
rng.Delete
End Sub
Well let me describe your scenary:
You have a list in this case your list is
sString = "Declined/Self ACH" (for this example your list have 2 elements)
then you have a table that have at least 17 columns ( Set aCell = .Columns(17).Find) and with your program you search all rows that have in column 17 a value that is in your list then put all that "rows" in a range (delRange) and delete all rows in that range
In this point your code only find firts match for each element in your list so you Range (delRange) have maximum size equal maximum size your list (for this example 2).
OK for me:
Why you save a range with elements that you are going to delete?
you can insert a delete instruction in second loop that others user suggest you, but instead use .Findnext you use another .find
PO=17 /*PO is whatever column you want*/
For i = LBound(MyAr) To UBound(MyAr)
Set aCell = .Columns(PO).Find(What:=MyAr(i), LookIn:=xlValues)
If Not aCell Is Nothing Then
Do
.Rows(aCell.Row).Delete
Set aCell = .Columns(PO).Find(What:=MyAr(i), LookIn:=xlValues)
Loop While Not aCell Is Nothing
End If
Next i

VBA - Using Current Selection As Range Object

I have this function below which does the following:
Takes two parameters (Header Name, Function Needed).
The Header Name parameter is used to find the heading and subsequently to identify the range of that column up until the last row.
The Function Needed parameter is used to switch in the select statement for any additional steps needed.
At the end of most of the statements, I do a Range.Select then I exit my function with a selected range.
Here is the code:
Function find_Header(header As String, fType As String)
Dim aCell As Range, rng As Range
Dim col As Long, lRow As Long
Dim colName As String
With ActiveSheet
Set aCell = .Range("B2:J2").Find(What:=header, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
'If Found
If Not aCell Is Nothing Then
col = aCell.Column
colName = Split(.Cells(, col).Address, "$")(1)
lRow = Range(colName & .Rows.count).End(xlUp).Row + 1
Set myCol = Range(colName & "2")
Select Case fType
Case "Copy"
'This is your range
Set rng = Range(myCol.Address & ":" & colName & lRow).Offset(1, 0)
rng.Select
End Select
'If not found
Else
MsgBox "Column Not Found"
End If
End With
End Function
As I am trying to clean up my code, I have come across a section where I have specifically hard coded ranges and I am trying to make use of my function instead, however, I am now at a point where I am unable to make use of this function correctly as I cannot "pass" the range back to the sub and I cannot seem to make the selection the range object needed for the sub.
Here is what is in the sub:
Sub Copy_Failed()
Dim xRg As Range, xCell As Range
Dim i As Long, J As Long, count As Long
Dim fType As String, colName As String
Dim y As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
myarray = Array("Defect", "System", "Script")
myEnv = Array("SIT", "UAT")
myDefects = Array("New", "Existing")
i = Worksheets("Run Results").UsedRange.Rows.count
J = Worksheets("Failed").UsedRange.Rows.count
Set y = Workbooks("Template.xlsm")
Set ws1 = y.Sheets("Failed")
Set ws2 = y.Sheets("Run Results")
count = 3
If J = 1 Then
If Application.WorksheetFunction.CountA(ws1.UsedRange) = 0 Then J = 0
End If
ws2.Activate
fType = "Copy"
colName = "Status"
Call find_Header(colName, fType)
End Sub
Before I used the function, the code looked like this:
lngLastRow = Cells(Rows.count, "B").End(xlUp).Row
Set xRg = ws2.Range("E3:E" & lngLastRow & i)
Now these 2 lines are performed in the function, so I don't need it in the sub. I have tried the following:
Set rngMyRange = Selection
Set rngMyRange = ActiveSheet.Range(Selection.Address)
Set xRg = ws2.Range(rngMyRange & i)
But I get the error:
Type mismatch
So I am thinking this:
Select the range in the function then use it in the sub - but how?
Figure out how to pass the actual range object from my function to the sub
Although the second option would require some extra changes in my code, I would think this is the better option to go with.
Ok, so here is an illustration just so you can see what I mean. If you put "one" somewhere in B2:J2 it will select the range. I am only using Select here so that you can see the range it identifies. (Disclaimer: I don't fully understand what you are doing, and not sure you need all this code to achieve what you want.)
The Function now returns a range variable, and is assigned to r. Run the procedure x.
Sub x()
Dim r As Range
Set r = Range("a1", find_Header("one", "Copy"))
r.Select
End Sub
Function find_Header(header As String, fType As String) As Range
Dim aCell As Range, rng As Range
Dim col As Long, lRow As Long
Dim colName As String
With ActiveSheet
Set aCell = .Range("B2:J2").Find(What:=header, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
'If Found
If Not aCell Is Nothing Then
col = aCell.Column
colName = Split(.Cells(, col).Address, "$")(1)
lRow = Range(colName & .Rows.Count).End(xlUp).Row + 1
Set myCol = Range(colName & "2")
Select Case fType
Case "Copy"
'This is your range
Set find_Header = Range(myCol.Address & ":" & colName & lRow).Offset(1, 0)
End Select
'If not found
Else
Set find_Header = Nothing
End If
End With
End Function

Compare and Copy from one spreadsheet to another

There are two Excel workbooks, Master and Survey Responses.
I have to loop through each row in Survey Responses, to select the value from the 4th column and compare it to the 4th column in Master. If there is no match then copy the complete row from Survey Responses to the end of Master. For the first time there will be no rows in Master so all rows must be copied from Survey Responses.
Survey Responses
The below code does not loop through all rows and if I run it a second time it copies all rows without performing the comparison.
'''''Define Object for Target Workbook
Dim Target_Workbook As Workbook
Dim Source_Workbook As Workbook
Dim Source_Path As String
'''''Assign the Workbook File Name along with its Path
Source_Path = "C:\Users\Survey Responses\Survey Response.xls"
Set Source_Workbook = Workbooks.Open(Source_Path)
Set Target_Workbook = ThisWorkbook
'''''With Source_Workbook object now, it is possible to pull any data from it
'''''Read Data from Source File
'''''Logic to select unique rows only
Dim rngSource As Range, rngTarget As Range, cellSource As Range, cellTarget As Range
Set rngSource = Source_Workbook.Sheets(1).Range("Responses")
Set rngTarget = Target_Workbook.Sheets(2).Range("Responses")
Dim rowNr_target As Integer, Rng As Range
With Target_Workbook.Sheets(2)
rowNr_target = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Dim counter As Integer, found As Boolean, inner_counter As Integer
counter = 1
For Each cellSource In rngSource.Rows
'On Error Resume Next
If cellSource.Cells(counter, 1).Value = "" Then
Exit For
End If
found = False
inner_counter = 1
For Each cellTarget In rngTarget.Rows
If cellTarget.Cells(inner_counter, 1).Value = "" Then
Exit For
End If
''''test = Application.WorksheetFunction.VLookup(test1, rngTarget, 1, False)
If (cellSource.Cells(counter, 4) = cellTarget.Cells(inner_counter, 4)) Then
found = True
Exit For
End If
inner_counter = inner_counter + 1
Next
If (found = False) Then
cellSource.EntireRow.Copy
If (rowNr_target > 1) Then
rngTarget.Rows(rowNr_target + 1).Insert
Else
rngTarget.Rows(rowNr_target).Insert
End If
rowNr_target = rowNr_target + 1
End If
counter = counter + 1
'On Error GoTo 0
Next
'''''Target_Workbook.Sheets(2).Range("Responses").Value = Source_data
'''''Close Target Workbook
Source_Workbook.Save
Target_Workbook.Save
''''Source_Workbook.Close False
'''''Process Completed
MsgBox "Task Completed"
Updated code:
Dim cel As Range
Dim rng As Range
Dim r As Range
Dim lastrow As Long
Dim Target_Workbook As Workbook
Dim Source_Workbook As Workbook
Dim Source_Path As String
'''''Assign the Workbook File Name along with its Path
Source_Path = "C:\Users\Survey Responses\Survey Response.xls"
Set Source_Workbook = Workbooks.Open(Source_Path)
Set Target_Workbook = ThisWorkbook
Dim rngSource As Range, rngTarget As Range, cellSource As Range, cellTarget As Range
Set rngSource = Source_Workbook.Sheets(1).Range("Responses")
Set rngTarget = Target_Workbook.Sheets(2).Range("Responses")
With Target_Workbook.Sheets(2)
lastrow = .Cells(.Rows.Count, 1).End(xlUp).Row
For Each cel In Source_Workbook.Sheets(1).Range("D:D")
If cel.Value = "" Then
Exit For
End If
Set r = .Range("D:D").Find(What:=cel, LookIn:=xlFormulas, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If r Is Nothing Then
cel.EntireRow.Copy
rngTarget.Rows(lastrow).Insert
''If Not rng Is Nothing Then Set rng = Union(rng, cel) Else Set rng = cel
End If
Next cel
''rng.Copy.Range("A" & lastrow).PasteSpecial xlPasteValues
End With
'''''Close Target Workbook
Source_Workbook.Save
Target_Workbook.Save
''''Source_Workbook.Close False
'''''Process Completed
MsgBox "Task Completed"
This is untested code but it should help you with anything you already have. You will need to adjust the ranges to suit yourself, but it will loop through one sheet and collect values that dont exists and then copy them to another sheet.
Try this,
Sub dave()
Dim cel As Range
Dim rng As Range
Dim r As Range
Dim lastrow As Long
With Sheets("Master")
lastrow = .Cells(.Rows.Count, 1).End(xlUp).Row
For Each cel In Sheets("Sheet1").Range("D1:D22")
Set r = .Range("D:D").Find(What:=cel, LookIn:=xlFormulas, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If r Is Nothing Then
If Not rng Is Nothing Then Set rng = Union(rng, cel) Else Set rng = cel
End If
Next cel
rng.Copy
.Range("A" & lastrow).PasteSpecial xlPasteValues
End With
End Sub

Resources