Determining if VBA If Then Statement is necessary to code and how to fix Compile Error - excel

Trying to set a Range ("headers") that is from a cell containing "Period" to cell containing "Agent Split". At the end of the code I select all of these ranges to make sure it's working properly.
I had tweaked the following code that contained a For loop
Sub Rangeheaders_test()
Dim r As Long
Dim endRow As Long
Dim endCell As Range
Dim headers As Range
With ActiveSheet
endRow = 500
For r = 1 To endRow
If .Cells(r, "A").Value = "Period" Then
Set endCell = .Rows(r).Find(What:="Agent Split", LookIn:=xlValues,_
LookAt:=xlPart, After:=.Cells(r, "A"))
Set headers = .Range(.Cells(r, "A"), endCell)
End If
Next r
End With
headers.Select
End Sub
However this code ran through the ranges and only selected the last when I wish to select them ALL in order to test it. So I deleted the loop which left me with the following
With ActiveSheet
endRow = 500
r = 1 To endRow
If .Cells(r, "A").Value = "Period" Then
Set endCell = .Rows(r).Find(What:="Agent Split", LookIn:=xlValues,_
LookAt:=xlPart, After:=.Cells(r, "A"))
Set headers = .Range(.Cells(r, "A"), endCell)
End If
End With
headers.Select
But now I'm either getting a Syntax Error or Compile error for Unexpected With or If close and I'm stuck. Do I need to define the Then condition? Is the If Then statement even necessary? Is there another way i can set the conditions?

I realized from #Jun 's insightful comment that i was trying to store multiple ranges in one variable and that's where i was going wrong.
After some research i found the Union method where I'm able to combine my ranges after i specify them -- which i did using the .Findnext method
Sub findheader()
Dim startcell As Range
Dim rng As Range
Set rng = Range("A1:A500")
Set startcell = rng.Find(what:="Period", LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:=False)
Dim header1, header2, header3 As Range
Set header1 = Range(startcell, startcell.End(xlToRight))
Set startcell = rng.FindNext(startcell)
Set header2 = Range(startcell, startcell.End(xlToRight))
Set startcell = rng.FindNext(startcell)
Set header3 = Range(startcell, startcell.End(xlToRight))
Dim headers As Range
Set headers = Union(header1, header2, header3)
headers.Select
End Sub

Related

Highlighting Values In Column to Column Comparison using VBA

I am attempting to compare two columns in two separate sheets, each column contains data that is a string. My issue is that there is data in one column that is identical to the other in separate rows; therefore I have to check the entire column for the data before moving to the next. I am very inexperienced with VBA and am trying to make one portion of my job easier rather than comparing the columns by hand. I have piece wised the following code from research and trial and error. I am able to get the entire Column searched in my first Sheet, but only one value is being highlighted on the second sheet and then it is returning a value of "True" in the first column. I am unsure where I have gone wrong, any help is greatly appreciated!
Sub Better_Work_This_Time()
Dim FindString As String
Dim Rng As Range
ActiveCell = Sheets("Last Week").Range("A2").Activate
FindString = ActiveCell
Dim County As Integer
Count = Cells.CurrentRegion.rows.Count
For i = 2 To County
If Trim(FindString) <> "" Then
With Sheets("Current Week").Range("A:A")
Set Rng = .Find(What:=FindString, After:=.Cells(.Cells.Count), LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=True)
If Not Rng Is Nothing Then
ActiveCell.Font.Color = vbBlue
End If
End With
End If
If IsEmpty(FindString) Then
FindString = False
End If
ActiveCell.Offset(1, 0).Select
i = i + 1
Next
End Sub
Without using ActiveCell and using Match instead of Find.
Option Explicit
Sub Does_Work_This_Time()
Dim wb As Workbook, wsLast As Worksheet, wsCurrent As Worksheet
Dim FindString As String, ar, v
Dim LastRow As Long, i As Long, n As Long
Set wb = ThisWorkbook
' put current week values into array
Set wsCurrent = wb.Sheets("Current Week")
With wsCurrent
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
ar = .Range("A2:A" & LastRow).Value2
End With
' scan last week matching current week
Set wsLast = wb.Sheets("Last Week")
With wsLast
.Columns(1).Interior.Color = xlNone
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 2 To LastRow
FindString = Trim(.Cells(i, "A"))
If Len(FindString) > 0 Then
v = Application.Match(FindString, ar, 0)
If IsError(v) Then
'no match
ElseIf ar(v, 1) = FindString Then ' case match
.Cells(i, "A").Interior.Color = RGB(128, 255, 128) ' light green
n = n + 1
End If
End If
Next
End With
MsgBox n & " rows matched"
End Sub

How to find all in specific column and replace based on another worksheet column data?

I have two worksheets, one generated automatically by another Macro I already have, this one generates data in a new WorkSheet called "SheetN" where N is a numerical value that depends on how many times this macro has been executed.
Then, in my PrincipalSheet I have something like:
Column R
User1; User2; User3;
User2; User4;
User2; User3; User5; User6;
In my auto generated SheetN I have:
Column B
User3;
User2;
NAN
I want to be able to iterate through SheetN column B until is empty and make a find all based on every row that is not NAN and then replace with "" in the PrincipalSheet:
Column R
User1;
User4;
User5; User6;
So far I have an idea to do something like
Sub Test2()
Dim i As Integer
Dim max As Integer
i = 1
i = 20
While i < max
If IsNot IsEmpty(ThisWorkbook.Sheets(NewSheet).Cells(2, i)) Then
MsgBox ThisWorkbook.Sheets(NewSheet).Cells(2, i)
End If
i = i + 1
Wend
End Sub
To retrieve the values from SheetN but this is not working, I'd really appreciate some help.
In the code I admitted that in SheetN columnB you can have duplicate values.
Sub ReplaceUserWithBlank()
Dim ws1 As Worksheet: Set ws1 = Sheets("Principal")
Dim ws2 As Worksheet: Set ws2 = Sheets("SheetN")
Dim lRowColB As Long: lRowColB = ws2.Cells(Rows.Count, "B").End(xlUp).Row
Dim lRowColR As Long: lRowColR = ws1.Cells(Rows.Count, "R").End(xlUp).Row
Dim rngColB As Range: Set rngColB = ws2.Range("B2:B" & lRowColB)
Dim rngColR As Range: Set rngColR = ws1.Range("R2:R" & lRowColR)
Dim rngTemp As Range: Set rngTemp = ws2.Range("K2:K" & lRowColB)
' copy column B to temporary column 'K'
rngColB.Copy rngTemp
' set range in column 'K'
Set rngTemp = Range(rngTemp, rngTemp.End(xlDown))
' Remove dulipcates
rngTemp.RemoveDuplicates Columns:=1, Header:=xlNo
' reset rngTemp
Set rngTemp = ws2.Range("K2", ws2.[K2].End(xlDown))
' Replace with blank
Dim rCell As Range
For Each rCell In rngTemp
rngColR.Replace What:=rCell.Value, Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False, FormulaVersion:=xlReplaceFormula2
Next rCell
' Trim and Clean
For Each rCell In rngColR
rCell.Value = Application.WorksheetFunction.Clean(Trim(rCell.Value))
Next rCell
' Clear temporary range 'K'
rngTemp.Clear
End Sub

Find all option for one column only

Good morning,
I am trying to narrow down my find all search option in VBA Excel.
The original example comes from this link:
https://www.excelcampus.com/tools/find-all-vba-form-for-excel/
where you can download the files with the find all tool both for active worksheet as well as a whole workbook.
I would like to set it in the custom worksheet instead of the active one.
According to the hint based in the comment:
Go to line 46 in the code “Set SearchRange =
ActiveSheet.UsedRange.Cells”
6. Change this to “Set SearchRange = ActiveSheet.Range(Cells(1, 1), Cells(Rows.Count, 1).End(xlUp))”
https://www.excelcampus.com/wp-content/uploads/2013/06/Find-All-Form-Search-1st-Column.png
I should only replace the SearchRange variable.
I did it, making my whole code like this:
Sub FindAllMatches()
'Find all matches on activesheet
'Called by: TextBox_Find_KeyUp event
Dim SearchRange As Range
Dim FindWhat As Variant
Dim FoundCells As Range
Dim FoundCell As Range
Dim arrResults() As Variant
Dim lFound As Long
Dim lSearchCol As Long
Dim lLastRow As Long
If Len(f_FindAll.TextBox_Find.Value) > 1 Then 'Do search if text in find box is longer than 1 character.
Set SearchRange = Sheets("Tracker").Range(Cells(1, 1), Cells(Rows.Count, 1).End(xlUp))
'Set SearchRange = Activesheet.UsedRange.Cells - original input
FindWhat = f_FindAll.TextBox_Find.Value
'Calls the FindAll function
Set FoundCells = FindAll(SearchRange:=SearchRange, _
FindWhat:=FindWhat, _
LookIn:=xlValues, _
LookAt:=xlPart, _
SearchOrder:=xlByColumns, _
MatchCase:=False, _
BeginsWith:=vbNullString, _
EndsWith:=vbNullString, _
BeginEndCompare:=vbTextCompare)
If FoundCells Is Nothing Then
ReDim arrResults(1 To 1, 1 To 2)
arrResults(1, 1) = "No Results"
Else
'Add results of FindAll to an array
ReDim arrResults(1 To FoundCells.Count, 1 To 2)
lFound = 1
For Each FoundCell In FoundCells
arrResults(lFound, 1) = FoundCell.Value
arrResults(lFound, 2) = FoundCell.Address
lFound = lFound + 1
Next FoundCell
End If
'Populate the listbox with the array
Me.ListBox_Results.List = arrResults
Else
Me.ListBox_Results.Clear
End If
End Sub
I am getting the following error:
Application-defined or object-defined error
pointing exactly the line, which was changed:
Set SearchRange = Sheets("Tracker").Range(Cells(1, 1), Cells(Rows.Count, 1).End(xlUp))
Everything is alright when the one looks like this:
Set SearchRange = Sheets("Tracker").UsedRange.Cells
so I don't know where might be the problem.
From the thread here:
VBA Runtime Error 1004 "Application-defined or Object-defined error" when Selecting Range
I can guess, that my form is placed in the wrong worksheet (as you can see on the image above).
In this event I tried to change the 93rd line of code:
ActiveSheet.Range(strAddress).Select
to
Sheets("Tracker").Range(strAddress).Select
but the result is exactly the same.
I also tried to set the different range for my cells:
Set SearchRange = Sheets("Tracker").Range(Cells(4, 1), Cells(Rows.Count, 1).End(xlUp))
as my data starts from the column A4. Unfortunately still no result.
I believe, that my problem starts from the .Range statement. When I change the .Range to .Usedrange
then my error is:
Wrong number of arguments or invalid property assignment
Can anyone help me to solve this issue? I appreciate any help.
The only thing I can see is that the rowcount is done on the active sheet instead of the sheet 'tracker'
try changing
Set SearchRange = Sheets("Tracker").Range(Cells(1, 1), Cells(Rows.Count, 1).End(xlUp))
to
With Sheets("Tracker")
Set SearchRange = .Range(.Cells(1, 1), .Cells(1, .Cells(1, .Rows.Count).End(xlUp).Row))
End With
edit 5-6-2020 tested the code and realised that the format was incorrect.
We can alternatively set the fixed range instead and see this problem off
In place of
Set SearchRange = Sheets("Tracker").Range(Cells(1, 1), Cells(Rows.Count, 1).End(xlUp))
We can input
Set SearchRange = Sheets("Tracker").Range("A4:A4000")
However, it obligates us to take control of our range and keep the code updated as the amount our records is expanded.

VBA Find Next Occurrence

Hey I'm currently writing a macro in VBA (which I'm quite new at). The macro looks at a spreadsheet and finds specific column headers. It then clears the contents of any cell containing a zero. This part of my code works exactly how I want, the only issue is that it does not hand multiple occurrences of the column header...so it finds the first header, clears the contents, and ignores the second occurrence. I have tried multiple avenues whether it be looping to find it or using the .FindNext function. Any help would be appreciated. Thank you! My code is posted below:
Sub DeleteRows2()
Application.ScreenUpdating = True
Dim lastrow As Long
With ActiveSheet
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
'~~>Start of First Instance
'~~>dim variables and set initial values
Dim delaymaxheader As Range
Set delaymaxheader = Worksheets(ActiveSheet.Name).Range("A4:Z4").Find(what:="DELAY Spec Max", LookAt:=xlWhole, MatchCase:=False)
Dim delaymaxcolumn As Range
Set delaymaxcolumn = Range(Cells(5, delaymaxheader.Column), Cells(lastrow, delaymaxheader.Column))
'Set delaymaxcolumn = Range(delaymaxheader.Offset(1, 0), delaymaxheader.End(xlDown))
'~~>dim variables and set initial values
Dim delayminheader As Range
Set delayminheader = Worksheets(ActiveSheet.Name).Range("A4:Z4").Find(what:="DELAY Spec Min", LookAt:=xlWhole, MatchCase:=False)
Dim delaymincolumn As Range
Set delaymincolumn = Range(Cells(5, delayminheader.Column), Cells(lastrow, delayminheader.Column))
'Set delaymincolumn = Range(delayminheader.Offset(1, 0), delayminheader.End(xlDown))
'~~>dim variables and set initial values
Dim phasemaxheader As Range
Set phasemaxheader = Worksheets(ActiveSheet.Name).Range("A4:Z4").Find(what:="PHASE Spec Max", LookAt:=xlWhole, MatchCase:=False)
Dim phasemaxcolumn As Range
Set phasemaxcolumn = Range(Cells(5, phasemaxheader.Column), Cells(lastrow, phasemaxheader.Column))
'Set phasemaxcolumn = Range(phasemaxheader.Offset(1, 0), phasemaxheader.End(xlDown))
'~~>dim variables and set initial values
Dim phaseminheader As Range
Set phaseminheader = Worksheets(ActiveSheet.Name).Range("A4:Z4").Find(what:="PHASE Spec Min", LookAt:=xlWhole, MatchCase:=False)
Dim phasemincolumn As Range
Set phasemincolumn = Range(Cells(5, phaseminheader.Column), Cells(lastrow, phaseminheader.Column))
'Set phasemincolumn = Range(phaseminheader.Offset(1, 0), phaseminheader.End(xlDown))
'~~>Loop to delete rows with zero
'~~>Dim delaycount(5 To lastrow) As Integer
For i = 5 To lastrow
If Cells(i, delaymaxheader.Column) = 0 Then
Cells(i, delaymaxheader.Column).ClearContents
End If
If Cells(i, delayminheader.Column) = 0 Then
Cells(i, delayminheader.Column).ClearContents
End If
If Cells(i, phasemaxheader.Column) = 0 Then
Cells(i, phasemaxheader.Column).ClearContents
End If
If Cells(i, phaseminheader.Column) = 0 Then
Cells(i, phaseminheader.Column).ClearContents
End If
Next i
End Sub
You need to use the FindNext method to keep going (https://msdn.microsoft.com/en-us/library/office/ff839746.aspx)
LastRow is only the last row of column A though - what happens if another column goes further?
Also Worksheets(ActiveSheet.Name).Range("A4:Z4") is the same as ActiveSheet.Range("A4:Z4").
Public Sub DeleteRows()
Dim colAllRanges As Collection
Dim colHeadings As Collection
'Declared as variants as they're used to step through the collection.
Dim vHeading As Variant
Dim vRange As Variant
Dim vCell As Variant
Dim rDelayMaxHeader As Range
Dim sFirstAddress As String
Dim lLastRow As Long
With ActiveSheet
lLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Set colAllRanges = New Collection
Set colHeadings = New Collection
colHeadings.Add "DELAY Spec Max"
colHeadings.Add "DELAY Spec Min"
colHeadings.Add "PHASE Spec Max"
colHeadings.Add "PHASE Spec Min"
For Each vHeading In colHeadings
With ActiveSheet.Range("A4:Z4")
'Find the first instance of the heading we're looking for.
Set rDelayMaxHeader = .Find(What:=vHeading, LookIn:=xlValues, LookAt:=xlWhole)
If Not rDelayMaxHeader Is Nothing Then
sFirstAddress = rDelayMaxHeader.Address
Do
'Resize the range from heading to last row and add it to the collection.
colAllRanges.Add rDelayMaxHeader.Resize(lLastRow - rDelayMaxHeader.Row + 1, 1)
'Find the next occurrence.
Set rDelayMaxHeader = .FindNext(rDelayMaxHeader)
'Keep going until nothings found or we loop back to the first address again.
Loop While Not rDelayMaxHeader Is Nothing And rDelayMaxHeader.Address <> sFirstAddress
End If
End With
Next vHeading
'Now to go through each cell in the range we've added to the collection and check for 0's.
For Each vRange In colAllRanges
For Each vCell In vRange
If vCell = 0 Then
vCell.ClearContents
End If
Next vCell
Next vRange
End Sub
With the above method you can add extra columns if needed - just add another colHeadings.Add "My New Column Header" row in the code.

Not getting values of all rows after auto filtering with for loop

I am struggling for writing the code - below query please help any one on writing it.
TestDataSheetName = ActiveWorkbook.Worksheets(x).Name
ActiveWorkbook.Worksheets(x).Activate
CountTestData = ActiveWorkbook.Worksheets(x).Range("A" & Rows.Count).End(xlUp).Row
Range("A10").Select
Range("A10").AutoFilter
Selection.AutoFilter Field:=14, Criteria1:=">=" & DateToday
ActiveWorkbook.Worksheets(x).Activate
CountTestDataAftFilter = ActiveWorkbook.Worksheets(x).Range("A1", Range("A65536").End(xlUp)).SpecialCells(xlCellTypeVisible).Count
MsgBox CountTestDataAftFilter
For w = 10 To CountTestDataAftFilter
Set Foundcell1 = ActiveWorkbook.Worksheets(x).Cells.Find(What:=DateToday, After:=[ActiveCell], _
SearchOrder:=xlByRows, SearchDirection:=xlNext, _
LookIn:=xlValues, LookAt:=xlPart, MatchCase:=True)
Next
' after filtering with today's date i got 5 rows with today's date and i have written for loop for getting all row values but after finding first row then it is not finding the second row value and it is again start with first row
Please help me on above code.
Thanks&Regards,
Basha
You're looking for the .FindNext function. Try something like this: (Please note, you may need to modify this code slightly to fit your particular case.)
Sub UseFindNext()
Dim TestDataSheet As Worksheet
Dim FoundCell1 As Range
Dim DateToday As Date
Dim firstAddress As String
Dim x As Long
Dim CountTestData As Long
Dim CountTestDataAftFilter As Long
x = 1
Set TestDataSheet = ActiveWorkbook.Worksheets(x)
CountTestData = TestDataSheet.Range("A" & Rows.count).End(xlUp).Row
Range("A10").AutoFilter Field:=14, Criteria1:=">=" & DateToday
CountTestDataAftFilter = TestDataSheet.Range("A1", Rows.count).End(xlUp)).SpecialCells(xlCellTypeVisible).count
Set FoundCell1 = TestDataSheet.Cells.Find(What:=DateToday, After:=TestDataSheet.Range("A10"), _
SearchOrder:=xlByRows, SearchDirection:=xlNext, _
LookIn:=xlValues, LookAt:=xlPart, MatchCase:=True)
firstAddress = FoundCell1.Address
Do
'Do whatever you're looking to do with each cell here. For example:
Debug.Print FoundCell1.Value
Loop While Not FoundCell1 Is Nothing And FoundCell1.Address <> firstAddress
End Sub
I don't know why you have to go through each value.
You already used AutoFilter to get the data you want.
But here's another approach that might work for you.
Sub test()
Dim ws As Worksheet
Dim wb As Workbook
Dim DateToday As String 'i declared it as string for the filtering
Dim rng, cel As Range
Dim lrow As Long
Set wb = ThisWorkbook
Set ws = wb.Sheets(x)
DateToday = "Put here whatever data you want" 'put value on your variable
With ws
lrow = .Range("A" & .Rows.Count).End(xlUp).Row
.Range("N10:N" & lrow).AutoFilter Field:=1, Criteria1:=DateToday
'I used offset here based on the assumption that your data has headers.
Set rng = .Range("N10:N" & lrow).Offset(1, 0).SpecialCells(xlCellTypeVisible)
'here you can manipulate the each cell values of the currently filtered range
For Each cel In rng
cel.EntireRow 'use .EntireRow to get all the data in the row and do your stuff
Next cel
.AutoFilterMode = False
End With
End Sub
BTW, this is based on this post which you might want to check as well to improve coding.
It is a good read. Hope this helps.

Resources