I'm working on a VBA Macro for a database I have in Excel. I've got one Worksheet that stores information such as names, emails etc. (sadly those are not consistently placed in the same columns across all worksheets, but the email adresses span from "B:F"), this database is split into multiple worksheets. Except all those worksheets, I have also got one other worksheet ("Sheet2" in the code below) that stores all the email addresses that have assigned to my newsletter. (The only information in this sheet are the email addresses in the "A" column).
The VBA I'm working on should loop through all the email adresses that have subscribed to the newsletter ("Sheet2") and check if they're stored in "the database" - in the other sheets as well. If not, then give a warning - write "NOTFOUND" in the cell next to the email.
For some reason, VBA gives me a run-time error "Object doesn't support this property or method" on the row:
With Sheets(sheetIndex).Range("B:F").
Originally I thought that the reason for that is that I have not activated the Sheets, but I'm still getting the error.
The code I came up with so far:
Sub Search_for_emails()
Dim scanstring As String
Dim foundscan As Range
Dim lastRowIndex As Long
Dim ASheet As Worksheet
Set ASheet = Sheets("Sheet2")
lastRowInteger = ASheet.Range("A1", ASheet.Range("A1").End(xlDown)).Rows.Count
For rowNum = 1 To lastRowInteger
scanstring = Sheets("Sheet2").Cells(rowNum, 1).Value
For sheetIndex = 1 To ThisWorkbook.Sheets.Count
Sheets(sheetIndex).Activate
If Sheets(sheetIndex).Name <> "Sheet2" Then
With Sheets(sheetIndex).Range("B:F")
Set foundscan = .Find(What:=scanstring, LookIn:=xlValues, LookAt:=xlWhole, _
SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
End With
If foundscan Is Nothing Then
ASheet.Cells(rowNum, 2).Value = "NOTFOUND"
Else
' ASheet.Cells(rowNum, 2).Value = foundscan.Rows.Count
End If
End If
Next
Next rowNum
End Sub
Some points:
You should avoid Activate - no need for that.
You should always qualify things like
sheet or range, else Excel will use the active workbook /
sheet, and that is not always what you want.
There is a difference between the Sheets and the Worksheets collection. A Chart-sheet, for example, has no cells and therefore no Range.
You are declaring a variable lastRowIndex but uses lastRowInteger. To avoid such errors, always put Option Explicit at the top of your code.
Change your Sub to
Sub Search_for_emails()
Dim scanstring As String
Dim foundscan As Range
Dim lastRowIndex As Long, rowNum As Long
Dim ASheet As Worksheet
Set ASheet = ThisWorkbook.Worksheets("Sheet2")
lastRowIndex = ASheet.Range("A1", ASheet.Range("A1").End(xlDown)).Rows.Count
For rowNum = 1 To lastRowIndex
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "Sheet2" Then
With ws.Range("B:F")
Set foundscan = .Find(What:=scanstring, LookIn:=xlValues, LookAt:=xlWhole, _
SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
End With
If foundscan Is Nothing Then
ASheet.Cells(rowNum, 2).Value = "NOTFOUND"
Else
' ASheet.Cells(rowNum, 2).Value = foundscan.Rows.Count
End If
End If
Next
Next rowNum
End Sub
Related
I need to handle an Excel workbook with multiple tabs, and format dates.
I have found a way to format one date, and I wanted to put a loop around it. However the loop does not work, and it only updates one sheet.
Sub dotoall()
Dim LastRow As Integer
Dim FindCol As Range
Dim sAdd As String
Dim ws As Worksheet
For Each Sheet In Worksheets
Set ws = ActiveSheet
With ws
LastRow = .Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
'find first instance where DATE exists in row 1 (headers)
Set FindCol = .Rows(1).Find(What:="DTE", LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False)
'store address of first found instance (to check in loop)
sAdd = FindCol.Address
Do
'format column (row 2 to last used row)
.Range(.Cells(2, FindCol.Column), .Cells(LastRow, FindCol.Column)).NumberFormat = "DD-MM-YYYY"
'find next instance (begin search after current instance found)
Set FindCol = .Cells.FindNext(After:=FindCol)
'keep going until nothing is found or the loop finds the first address again (in which case the code can stop)
Loop Until FindCol Is Nothing Or FindCol.Address = sAdd
End With
Next Sheet
End Sub
Instead of:
For Each Sheet In Worksheets
Set ws = ActiveSheet
You want just:
For Each ws In Worksheets
New to coding so sorry if I'm completely ignoring contexts as I'm still trying to learn them.
I have cells that are trying to pull data from several Pivot Tables in another worksheet. If it is unable to pull any information from the pivot tables, it will return #REF. The Macro is supposed to search through in each cell within several ranges to search for the #REF and replace it with a 0. The reason its several ranges instead of the entire worksheet is that some of the equations are trying to add values from a table and since some of those values are #REF, the sum also ends up being #REF. I need to keep those equations there so once the #REF's are replaced, they would get the sum.
Dim Areas(13) As Range
Set Areas(1) = Range("C5:Z7")
Set Areas(2) = Range("C10:Z14")
Set Areas(3) = Range("C27:Z27")
Set Areas(4) = Range("C33:Z45")
Set Areas(5) = Range("C52:Z55")
Set Areas(6) = Range("C58:Z61")
Set Areas(7) = Range("C63:Z66")
Set Areas(8) = Range("C68:Z72")
Set Areas(9) = Range("C74:Z78")
Set Areas(10) = Range("C80:Z84")
Set Areas(11) = Range("C86:Z90")
Set Areas(12) = Range("C92:Z96")
Set Areas(13) = Range("C102:Z112")
For R = 1 To 13
For Each cell In Areas(R) 'Error: For Each may only iterate over a collection object
If cell.Value = CVErr(xlErrName) Then
.Replace What:="#REF!", Replacement:="0", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Else
Next
I made a bunch of notes after my code to try to work off of based on other StackOverflow questions which I listed below. I figured they worked will form a single range but I'm working with several. If none of what I did makes sense then disregard the below and help me start over. (Please?) Let me know if you need any more information.
If IsError(cell.Value) Then
' If cell.Value = CVErr(xlErrName) Then
' ...
' End If
'End If
'Dim nm As Name
' For Each nm In ActiveWorkbook.Names
' If InStr(nm.Value, "#REF!") > 0 Then
' nm.Delete
' End If
'Next nm
' ActiveCell.Replace What:="#REF!", Replacement:="0", LookAt:=xlPart, _
' SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
' ReplaceFormat:=False
'With Range("B11:AP55").SpecialCells(xlCellTypeFormulas)
' .Formula = Replace(.Formula, "#REF", "Master", , , vbTextCompare)
'End With
As an alternative to Find, consider SpecialCells
To remove only #REF errors
Sub Demo1()
Dim rng As Range
Dim rErr As Range
Dim cl As Range
With ActiveSheet 'or specify a specific sheet
Set rng = .Range("C5:Z7,C10:Z14,C27:Z27,C33:Z45,C52:Z55,C58:Z61,C63:Z66,C68:Z72,C74:Z78,C80:Z84,C86:Z90,C92:Z96,C102:Z112")
End With
On Error Resume Next
Set rErr = rng.SpecialCells(xlCellTypeFormulas, xlErrors)
On Error GoTo 0
If Not rErr Is Nothing Then
For Each cl In rErr.Cells
If cl.Value = CVErr(xlErrRef) Then
cl.Offset(0, 1) = 0
End If
Next
End If
End Sub
To remove All errors:
Sub Demo2()
Dim rng As Range
Dim rErr As Range
With ActiveSheet 'or specify a specific sheet
Set rng = .Range("C5:Z7,C10:Z14,C27:Z27,C33:Z45,C52:Z55,C58:Z61,C63:Z66,C68:Z72,C74:Z78,C80:Z84,C86:Z90,C92:Z96,C102:Z112")
End With
On Error Resume Next
Set rErr = rng.SpecialCells(xlCellTypeFormulas, xlErrors)
On Error GoTo 0
If Not rErr Is Nothing Then
rErr = 0
End If
End Sub
I have two spreadsheets. Each spreadsheet contains rows with various bits of information on them, including a unique identifier number (an ISBN in this case).
I am trying to make a script that determines a record is present on the working sheet (obtaining ISBN from column A – working sheet is called ePubWorking), and marks a column (V) on the master sheet (ePubMaster) in the row that contains the same ISBN as found on the previous sheet (the ISBN on the new sheet is also kept in column A). It needs to do this for each record found on the ePubWorking sheet.
I’ve tried a few variants of code I’ve found on here, but I can’t seem to get anything to work. This is what I’m currently working with (which doesn’t appear to be doing anything):
Dim rCell As Range
Dim rFind As Range
Dim iColumn As Integer
For Each rCell In Sheets("ePubWorking").Range("A2", Sheets("ePubWorking").Cells(Rows.Count, "A").End(xlUp))
Set rFind = Sheets("ePubMaster").Rows(1).Find(What:=Trim(rCell.Value), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
rCell.Offset(0, 2).Value = "Sent"
If Not rFind Is Nothing Then
rFind.Offset(0, 21).Value = "Sent"
End If
Next rCell
Nothing is happening using the above (or any of my other variants). I can't even get the "Sent" part to appear on the secondary sheet.
Can anyone point me in the right direction please?
Ok so thanks for the guidance, obviously I'd been banging my head on frankenstein attempts for too long and got blinded to what I was doing. As Zac pointed I was looking along the wrong axis on the ePubMaster sheet.
Working code:
Dim wb As Workbook: Set wb = ThisWorkbook
Dim workingSheet As Worksheet: Set workingSheet = wb.Sheets("ePubWorking")
Dim masterSheet As Worksheet: Set masterSheet = wb.Sheets("ePubMaster")
Dim workingRange As Range: Set workingRange = Range(workingSheet.Range("A2"), workingSheet.Cells(workingSheet.Rows.Count, "A").End(xlUp))
Dim rCell As Range
Dim rFind As Range
For Each rCell In workingRange
If Not rCell.Value = vbNullString Then
Set rFind = masterSheet.Rows.Find(What:=Trim(rCell.Value), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
rCell.Offset(0, 2).Value = "Sent"
If Not rFind Is Nothing Then
rFind.Offset(0, 21).Value = "Sent"
End If
End If
Next rCell
I am trying to achieve the following:
I have a VBA button that when clicked, copies the active worksheet and pastes it into a new worksheet (I have this function already working perfectly - see code below).
I then want the newly pasted worksheet to find two specified cells, which contain the texts ("bus start") and ("bus finish") and clear all the contents in the cells that are in between the range of the two specified cells.
The rows are dynamic and will change over time as rows get added and deleted, hence why I cannot define a fixed range. Columns however, will not be deleted or added and therefore will be fixed.
For reference, here is my copy and paste code:
Private Sub WkCapBtn_Click()
Dim Ws1 As Worksheet
Set Ws1 = ActiveSheet
Ws1.Copy ThisWorkbook.Sheets(Sheets.Count)
ActiveSheet.Range("C3").Value = DateAdd("d", 7, ActiveSheet.Range("C3"))
ActiveSheet.Name = Format(ActiveSheet.Range("A1").Value, ("dd-mmm-yy"))
End Sub
My initial thinking was to use a .Find function to locate the specified cells and then use a .Offset to select the cells below and above. Where I am stuck though is actually trying to define the range between the specified cells.
If any additional information is needed, please let me know. Thank you in advance!
I corrected your code a little for the beginning:
Static WsCopy As Worksheet
Static Ws1 As Worksheet
Private Sub WkCapBtn_Click()
Set Ws1 = ThisWorkbook.Sheets("ORIGINALSHEETNAME")
Set WSCopy = Ws1.Copy After:=(ThisWorkbook.Sheets(Sheets.Count))
With WSCopy
.Name = Format(.Range("A1").Value, ("dd-mmm-yy"))
.Range("C3").Value = DateAdd("d", 7, .Range("C3"))
End With
End Sub
For your other sub you could set a variable for the cells containing either "bus start" or "bus finish". Can you try the following code and tell me if it worked?
Private Sub DelBusRange()
Dim BusStart As Range
Dim BusFinish As Range
With WsCopy
Set BusStart = .Find(What:="Bus start", _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
Set BusFinish = .Find(What:="Bus finish", _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
.Range(BusStart, BusFinish).clear
End With
End Sub
Chris Neilson's code did the trick once I changed it around.
Private Sub WkCapBtn_Click()
Dim Ws1 As Worksheet
Dim FindBus1 As String
Dim FindBus2 As String
Dim BusMatch1 As Range
Dim BusMatch2 As Range
Set Ws1 = ActiveSheet
Ws1.Copy ThisWorkbook.Sheets(Sheets.Count)
ActiveSheet.Range("C3").Value = DateAdd("d", 7, ActiveSheet.Range("C3"))
ActiveSheet.Name = Format(ActiveSheet.Range("A1").Value, ("dd-mmm-yy"))
FindBus1 = "Bus Start"
FindBus2 = "Bus Finish"
Set BusMatch1 = ActiveSheet.Cells.Find(FindBus1)
Set BusMatch2 = ActiveSheet.Cells.Find(FindBus2)
ActiveSheet.Range(BusMatch1.Offset(3, 1), BusMatch2.Offset(-2, 1)).ClearContents
End Sub
I am working on a project and I have got a point where I want to copy certain data from one sheet to another. E.g. if in column "A" a cell contains "Hello" then copy what is in cell "E4". Would an "IF" statement would work?
The code I have so far for my project is
Sub testfortito()
Dim x As Workbook
Dim y As Workbook
Dim ws As Worksheet
'this opens both workbooks
Set x = Workbooks.Open("Location1")
Set y = Workbooks.Open("Location2")
'to do the copy
x.Sheets("sheet3").Range("A2:AC2").Copy
For Each ws In Worksheets
If ws.Name <> "sheet3" Then
ws.Range("E3").Copy
Worksheets ("Sheet3")
End If
Next ws
End Sub
Try this
Sub testfortito()
Dim colEtxt(), ctr
ctr = 0
With Sheet1.Range("A:A")
Set txt = .Find(What:="hello", LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
If Not txt Is Nothing Then
firstAddress = txt.Address
Do
ReDim Preserve colEtxt(ctr)
colEtxt(ctr) = Range(txt.Address).Offset(0, 4).Value
Set txt = .FindNext(txt)
ctr = ctr + 1
Loop While Not txt Is Nothing And txt.Address <> firstAddress
End If
End With
'copy the array onto sheet2 using transpose technique
Sheet2.Range("A1:A" & UBound(colEtxt) + 1) = WorksheetFunction.Transpose(colEtxt)
End Sub