unable to set workbook variable to ActiveWorkbook - vba

This is blowing my mind. I can't find what I'm doing wrong. I hope it's just a case of tunnel vision.
I get error message "Object variable or With block variable not set- 1"
Option Explicit:
Public mWB As Workbook
Public Sub runCSSBatch()
On Error GoTo Errorcatch
1 mWB = ActiveWorkbook
Call createTempSheet
Call findworksheet
Errorcatch:
MsgBox Err.Description & "-" & Erl
Application.DisplayAlerts = False
mWB.Sheets("TEMP").Delete
Application.DisplayAlerts = True
End Sub

Instead of ActiveWorkbook, it may be, ThisWorkbook
set mwb=thisworkbook

I eventually found many things wrong with my script.
I did end up using Set in front of ActiveWorkbook (using ThisWorkbook
was not necessary)
I believe the comment about using 1: instead of 1 to catch the error
was valid.
I am now running the script with quite a few less subs than I was
before.
I also had made the mistake of using Cells() inside Range() when one
excludes the other
I tried to pass a Worksheet Variable to a Sub (apparently you can't
do that).
I'm sure there was more but I can't recall.
I'm going to chalk it up to having a shitty day. :/
As you can see the below code looks nothing like what I had posted initially.
Option Explicit:
Public mWB As Workbook
Public Sub runCSSBatch()
Set mWB = ActiveWorkbook
mWB.Sheets.Add.Name = "TEMP"
Dim WSh As Worksheet
For Each WSh In mWB.Worksheets
If InStr(WSh.Name, "CSS") = 1 Then
Call parseRowText(WSh.Name)
End If
Next
End Sub
Private Sub parseRowText(WSName As String)
Dim rowCount As Long
Dim I As Long
Dim columnCount As Long
Dim B As Long
Dim dataString As String
Dim WS As Worksheet
Set WS = mWB.Worksheets(WSName)
columnCount = mWB.Sheets(WSName).UsedRange.Columns.Count
rowCount = mWB.Sheets(WSName).UsedRange.Rows.Count
For I = 2 To rowCount
For B = 1 To columnCount
dataString = ""
If mWB.Sheets(WSName).Cells(1, B).Value = "STOP" Then
dataString = "}"
Call addToTempSheet(dataString)
Exit For
Else
If B = 1 Then
dataString = mWB.Sheets(WSName).Cells(I, B).Value & "{"
Call addToTempSheet(dataString)
Else
If dataString & mWB.Sheets(WSName).Cells(I, B).Value = "" Then
Else
dataString = mWB.Sheets(WSName).Cells(1, B).Value & ":"
dataString = dataString & mWB.Sheets(WSName).Cells(I, B).Value & ";"
Call addToTempSheet(dataString)
End If
End If
End If
Next B
Next I
End Sub
Private Sub addToTempSheet(dString As String)
mWB.Sheets("TEMP").Range("A" & Rows.Count).End(xlUp).Offset(1).Value = dString
End Sub

Related

VBA search for value on next sheet

is there I way for searching a value on the next sheet (ActiveSheet.Next.Activate) without jumping on to it?
Here the whole Code:
the problem is, it jumps to the next sheet even if there is no searched value.
Dim ws As Worksheet
Dim Loc As Range
Dim StrVal As String
Dim StrRep As String
Dim i As Integer
Private Sub CommandButton1_Click()
i = 1
Call Replacing
End Sub
Private Sub CommandButton2_Click()
i = 2
Call Replacing
End Sub
Public Sub Replacing()
StrVal = Userform1.Textbox1.Text
StrRep = Me.Textbox1.Text
if Trim(StrVal) = "" Then Exit Sub
Dim fstAddress As String
Dim nxtAddress As String
For Each ws In ThisWorkbook.Worksheets
With ws
Set Loc = .Cells.Find(what:=StrVal)
fstAddress = Loc.Address
If Not Loc Is Nothing Then
If Not StrRep = "" And i = 1 Then
Loc.Value = StrRep
Set Loc = .Cells.FindNext(Loc)
ElseIf i = 2 Then Set Loc = Range(ActiveCell.Address)
Set Loc = .Cells.FindNext(Loc)
nxtAddress = Loc.Address
If Loc.Address = fstAddress Then
ActiveSheet.Next.Activate '****Here it should jump only if found something on the next sheet****
GoTo repeat
nxtAddress = Loc.Address
End If
If Not Loc Is Nothing Then Application.Goto ws.Range(nxtAddress), False
End If
i = 0
End If
End With
Set Loc = Nothing
repeat:
Next ws
End Sub
the variable "i" which switches between the values 0, 1 and 2 is bound to two buttons. these buttons are "Replace" and "Skip (to next found value)".
This code asks on each occurrence of StrVal whether you want to replace the value or skip it.
I found a problem checking if Found_Address = First_Found_Address:
If you've replaced the value in in First_Found_Address it won't find that address again and miss the starting point in the loop.
Also the original source of the code stops at the last value using Loop While Not c Is Nothing And c.Address <> firstAddress. The problem here is that if the value in c is being changed eventually c will be Nothing but it will still try and check the address of c - causing an error (Range Find Method).
My solution to this is to build up a string of visited addresses on the sheet and checking if the current address has already been visited using INSTR.
I've included the code for calling from a button click or from within another procedure.
Private Sub CommandButton1_Click()
FindReplace Userform1.Textbox1.Text, 1
End Sub
Private Sub CommandButton2_Click()
FindReplace Userform1.Textbox1.Text, 1, Me.Textbox1.Text
End Sub
Sub Test()
FindReplace "cd", 1, "ab"
End Sub
Sub FindReplace(StrVal As String, i As Long, Optional StrRep As String = "")
Dim ws As Worksheet
Dim Loc As Range
Dim fstAddress As String
Dim bDecision As Variant
For Each ws In ThisWorkbook.Worksheets
'Reset the visited address list on each sheet.
fstAddress = ""
With ws
Set Loc = .Cells.Find(what:=StrVal, LookIn:=xlValues, LookAt:=xlWhole, SearchDirection:=xlNext)
If Not Loc Is Nothing Then
Do
fstAddress = fstAddress & "|" & Loc.Address
Loc.Parent.Activate 'Activate the correct sheet.
Loc.Activate 'and then the cell on the sheet.
bDecision = MsgBox("Replace value?", vbYesNo + vbQuestion, "Replace or Select value?")
If bDecision = vbYes Then
Loc = StrRep 'Raise the blade, make the change.
'Re-arrange it 'til it's sane.
End If
Set Loc = .Cells.FindNext(Loc)
If Loc Is Nothing Then Exit Do
Loop While InStr(fstAddress, Loc.Address) = 0
End If
End With
Next ws
End Sub

Excel VBA - If Else still performing Else

My code is fairly simple but a bit puzzling. I might be committing a minor error - pardon my newbie-ness. The Sheets.Add.Name line still gets executed despite having Boolean = True, thus a new worksheet is created with the Sheet# naming convention.
Sharing my code:
Private Sub create_analyst_btn_Click()
Dim strUser As String
Dim DateToday As String
Dim ws As Worksheet
Dim boolFound As Boolean
strUser = newanalyst_form.user_User.Value
For Each ws In Worksheets
If ws.Name Like strUser Then boolFound = True: Exit For
Next
If boolFound = True Then
MsgBox ("User already exists.")
Else
DateToday = Format(Date, "-yyyy-mm-dd")
Sheets.Add.Name = strUser & DateToday
Unload Me
End If
End Sub
I don't see the point of the first If statement and I would refactor your code to the following:
For Each ws In Worksheets
If ws.Name Like "*" & strUser & "*" Then
MsgBox ("User already exists.")
Exit For
Else
DateToday = Format(Date, "-yyyy-mm-dd")
Sheets.Add.Name = strUser & DateToday
Unload Me
End If
Next ws
The logic here is that if the name already exists before calling the subroutine, we would discover this while iterating, display a warning message in an alert box, and exit. Otherwise, the name/date would be added to the sheet.

Excel VBA - Data connection opens workbook visibly sometimes

When I make a call to open a connection to another workbook, occasionally the workbook will open fully in Excel. I have ~15 data sets I pull using this method and I have not been able to identify a pattern. yesterday the refresh was quick and seamless and no workbooks visibly opened in Excel. Today 1 of 2 is opening in Excel.
Since I have users of varying experience with Excel, I would like to eliminate this possibly confusing behavior.
oCnC.Open "Provider=Microsoft.ACE.OLEDB.12.0;Mode=Read;Data Source=" & Filename & ";Extended Properties=""Excel 12.0; HDR=YES;"";"
Example code:
sub Caller
Set dTabs = New Dictionary
Set dTabs("Cerner") = New Dictionary
dTabs("Cerner")("Query") = "Select Field1, Field2 from [Sheet1$]"
dTabs("Cerner")("Hidden") = 1
Call GetMasterTables("\\\Files\File1.xlsx", dTabs)
dTabs.RemoveAll
Set dTabs = New Dictionary
Set dTabs("SER") = New Dictionary
dTabs("SER")("Query") = "Select [1],F75 from [Sheet1$]"
dTabs("SER")("Hidden") = 1
Call GetMasterTables("\\Files\File2.xlsx", dTabs)
dTabs.RemoveAll
(Cleanup)
End Sub
Private Sub GetMasterTables(Filename As String, dTabset As Dictionary, ByRef wb As Workbook)
Dim oCnC As Connection
Dim rsC As Recordset
Dim rsE As Recordset
Dim lo As ListObject
Dim rngHome As Range
Set oCnC = New Connection
Set rsC = New Recordset
Set rsE = New Recordset
Dim ws As Worksheet
oCnC.Open "Provider=Microsoft.ACE.OLEDB.12.0;Mode=Read;Data Source=" & Filename & ";" & _
"Extended Properties=""Excel 12.0; HDR=YES;"";"
rsC.ActiveConnection = oCnC
For Each i In dTabset
If SheetExists(i, wb) Then
Set ws = wb.Sheets(i)
ws.Visible = xlSheetVisible
Else
Set ws = wb.Sheets.Add(, wb.Sheets(wb.Sheets.count))
ws.Name = i
ws.Visible = xlSheetVisible
End If
Set rngHome = ws.Range("A1")
If RangeExists("Table_" & Replace(i, "-", "_"), ws) Then
Set lo = ws.ListObjects("Table_" & Replace(i, "-", "_"))
lo.DataBodyRange.Delete
Else
Set lo = ws.ListObjects.Add(, , , xlYes, rngHome)
lo.Name = "Table_" & Replace(i, "-", "_")
lo.DisplayName = "Table_" & Replace(i, "-", "_")
End If
If dTabset(i).Exists("Query") Then
rsC.Source = dTabset(i)("Query")
Else
rsC.Source = "Select * from [" & i & "$]"
End If
rsC.Open
rsC.MoveFirst
ws.Range(lo.HeaderRowRange.Offset(1, 0).address).Value = "hi"
lo.DataBodyRange.CopyFromRecordset rsC
rsC.MoveFirst
For Each j In lo.HeaderRowRange.Cells
j.Value = rsC.Fields(j.Column - 1).Name
Next j
rsC.Close
If dTabset(i).Exists("Hidden") Then
ws.Visible = xlSheetHidden
Else
ws.Visible = xlSheetVisible
End If
Next i
End Sub
Function SheetExists(ByVal shtName As String, Optional wb As Workbook) As Boolean
Dim sht As Worksheet
If wb Is Nothing Then Set wb = ActiveWorkbook
On Error Resume Next
Set sht = wb.Sheets(shtName)
On Error GoTo 0
SheetExists = Not sht Is Nothing
End Function
Function RangeExists(ByVal rngName As String, Optional ws As Worksheet) As Boolean
Dim rng As ListObject
If ws Is Nothing Then Set ws = ActiveWorksheet
On Error Resume Next
Set rng = ws.ListObjects(rngName)
On Error GoTo 0
RangeExists = Not rng Is Nothing
End Function
Update 1
Ah-ha! I have an update.
After the last test I had left the workbook open. When I came back to the computer after a few minutes there was a prompt up that the file was available for editing. Perhaps the intermittent behavior is due to the requested file being open by another user. I tested this theory by closing the workbook and then re-running the sub and it did not open the file in the app.
Update 2
Qualified my sheets references. Issue is still happening.
The issue is here (and anywhere else you're using Sheets without an object reference):
Set ws = Sheets(i)
ws.Visible = xlSheetVisible
Sheets is a global collection of the Application, not the Workbook that the code is running from. Track down all of these unqualified references and make them explicit:
Set ws = ThisWorkbook.Sheets(i)
You should also pass your optional parameter here:
'SheetExists(i)
'...should be...
SheetExists(i, ThisWorkbook)
I'm guessing the reason this is intermittent is that you're catching instances where the ADO connection has the other Workbook active, and your references aren't pointing to where they're supposed to.
In addition to the code review offered by #Comintern and #YowE3K I found a solution in the following:
Qualify my workbooks, and my sheets
Turn off screen updating (so the users can't see my magic)
Throw the book names in a dictionary before I do my update and close any extras that opened during the update.
Application.ScreenUpdating = False
For i = 1 To Application.Workbooks.count
Set dBooks(Application.Workbooks(i).Name) = i
Next i
Application.ScreenUpdating = False
Code from question
For i = 1 To Application.Workbooks.count
If dBooks.Exists(Application.Workbooks(i).Name) Then
dBooks.Remove (Application.Workbooks(i).Name)
Else
dBooks(Application.Workbooks(i).Name) = i
End If
Next i
For Each bookname In dBooks
Application.Workbooks(bookname).Close (False)
Next
Application.ScreenUpdating = True

Delete Entire Rows from multiple Sheets

I need some help with a vba code that will delete and entire row from a different sheet from the currently active one.
The code uses a userform to delete a row based upon a serial number entered into a text box. The rows to delete are duplicated on the sheet the userform is activated from as well as another. Below is an example I have tried which will delete the row of the current sheet but sends back an error for the second portion of code in the Else command.
Private Sub ScrapButton_Click()
Dim RTCNumber As String
RTCNumber = RTCTextBox
MSG1 = MsgBox("Remove " + RTCTextBox + " from Lab Stock?", vbYesNo)
If MSG1 = vbNo Then
Exit Sub
Else
Dim Row As Integer
Row = Application.WorksheetFunction.Match(RTCNumber, Sheet6.Range("A:A"), 0)
Rows(Row).EntireRow.Delete
Dim Row2 As Integer
Row2 = Application.WorksheetFunction.Match(RTCNumber, Sheet1.Range("A:A"), 0)
Sheets("Sheet1").Rows(Row2).EntireRow.Delete
End If
End Sub
Any help would be much appreciated, I am probably missing something obvious but I am fairly new to vba. I have tried several options and can't get it to work using a Worksheet.Activate function.
Thanks in advance.
James
Try to CLng the first argument of your match function. That works for me.
Had to remove WorksheetFunction on my version of Excel, but I don't know if that's the case on your machine, so I left it in.
And then, as manu stated in his answer, I added Sheet references.
Private Sub ScrapButton_Click()
Dim RTCNumber As String
RTCNumber = RTCTextBox
MSG1 = MsgBox("Remove " + RTCTextBox + " from Lab Stock?", vbYesNo)
If MSG1 = vbNo Then
Exit Sub
Else
Dim Row As Integer
Row = Application.WorksheetFunction.Match(Clng(RTCNumber), Sheets("Sheet6").Range("A:A"), 0)
Rows(Row).EntireRow.Delete
Dim Row2 As Integer
Row2 = Application.WorksheetFunction.Match(Clng(RTCNumber), Sheets("Sheets1").Range("A:A"), 0)
Sheets("Sheet1").Rows(Row2).EntireRow.Delete
End If
End Sub
Try this:
Private Sub ScrapButton_Click()
Dim RTCNumber As Double
Dim Row2 As Variant
Dim Row1 As Variant
Dim wb As Workbook
Dim ws1 As Worksheet
Dim ws6 As Worksheet
Set wb = ThisWorkbook
Set ws1 = wb.Sheets("Sheet1")
Set ws6 = wb.Sheets("Sheet6")
RTCNumber = RTCTextBox
MSG1 = MsgBox("Remove " & RTCNumber & " from Lab Stock?", vbYesNo)
If MSG1 = vbNo Then
Exit Sub
Else
Row1 = ws6.Application.WorksheetFunction.Match(RTCNumber, ws6.Range("A:A"), 0)
ws6.Rows(Row1).EntireRow.Delete
Row2 = ws1.Application.WorksheetFunction.Match(RTCNumber, ws1.Range("A:A"), 0)
ws1.Rows(Row2).EntireRow.Delete
End If
End Sub
Brilliant, thanks for the help!
Managed to get it working with Manu's answer with a couple tiny tweaks. It ended up like this:
Private Sub ScrapButton_Click()
Dim RTCNumber As String
Dim Row2 As Variant
Dim Row1 As Variant
Dim wb As Workbook
Dim ws1 As Worksheet
Dim ws6 As Worksheet
Set wb = ActiveWorkbook
Set ws1 = wb.Worksheets("Lab Stock")
Set ws6 = wb.Worksheets("Scrap")
RTCNumber = RTCTextBox
MSG1 = MsgBox("Remove " & RTCNumber & " from Lab Stock?", vbYesNo)
If MSG1 = vbNo Then
Exit Sub
Else
Row1 = ws6.Application.WorksheetFunction.Match(RTCNumber, ws6.Range("A:A"), 0)
ws6.Rows(Row1).EntireRow.Delete
Row2 = ws1.Application.WorksheetFunction.Match(RTCNumber, ws1.Range("A:A"), 0)
ws1.Rows(Row2).EntireRow.Delete
End If
End Sub
Much, much appreciated!
You can use more simple way to achieve required results using range.find method.
So, your code can looks like this:
Private Sub ScrapButton_Click()
Dim RTCNumber As String
Dim Cl As Range
RTCNumber = RTCTextBox
msg1 = MsgBox("Remove " + RTCTextBox + " from Lab Stock?", vbYesNo)
If msg1 = vbNo Then
Exit Sub
Else
With Sheets("Sheet1")
Set Cl = .[A:A].Find(RTCNumber, , xlValues, xlWhole)
If Not Cl Is Nothing Then Cl.EntireRow.Delete
End With
With Sheets("Sheet6")
Set Cl = .[A:A].Find(RTCNumber, , xlValues, xlWhole)
If Not Cl Is Nothing Then Cl.EntireRow.Delete
End With
End If
End Sub
If you still prefer usage of worksheetfunction then you shall know that if worksheetfunction.match couldn't find the search value then it will return error, worksheetfunctions shall be used only with error handling.

Macros, using array to copy worksheets to a different workbook

We have an SSRS report that has a separate worksheet for each division. We run a macro to rename all the worksheets with the division name and then copy specific worksheets to a new workbook to be emailed to the divisions. The problem with the code is that if one of the divisions does not have a worksheet that month the macro errors out with an error of "not in specified range". Is there a way to tell it to ignore missing worksheets if they do not exist this time? Here is the code:
Sheets(Array("AB", "CD", "EF", "GH", "IJ", "KL")).Copy
Sheets("AB").Select
ActiveWorkbook.SaveAs Filename:= _
Path & "Holder Agings " & Today & ".xlsx", FileFormat:=xlOpenXMLWorkbook, _
Password:="", WriteResPassword:="", ReadOnlyRecommended:=False, _
CreateBackup:=False
Thank You!
I agree with Rusan Kax, without a complete block of code it is difficult to produce exactly the code you need. The code below shows two techniques. You should be able to adapt one of them to your requirements.
Option Explicit
Sub Test1()
' Demonstrate CheckWshts(Array) which removes names from the array
' if they do not match the name of a worksheet within the active
' workbook
Dim InxWsht As Long
Dim WshtTgt() As Variant
WshtTgt = Array("AB", "CD", "EF", "GH", "IJ", "KL")
Call CheckWshts(WshtTgt)
For InxWsht = LBound(WshtTgt) To UBound(WshtTgt)
Debug.Print WshtTgt(InxWsht)
Next
End Sub
Sub Test2()
' Demonstrates WorksheetExists(Name) which returns True
' if worksheet Name is present within the active workbook.
Dim InxWsht As Long
Dim WshtTgt() As Variant
WshtTgt = Array("AB", "CD", "EF", "GH", "IJ", "KL")
For InxWsht = LBound(WshtTgt) To UBound(WshtTgt)
If WorksheetExists(CStr(WshtTgt(InxWsht))) Then
Debug.Print WshtTgt(InxWsht) & " exists"
Else
Debug.Print WshtTgt(InxWsht) & " does not exist"
End If
Next
End Sub
Sub CheckWshts(WshtTgt() As Variant)
' * WshtTgt is an array of worksheet names
' * If any name is not present in the active workbook,
' remove it from the array
Dim Found As Boolean
Dim InxWshtActCrnt As Long
Dim InxWshtTgtCrnt As Long
Dim InxWshtTgtMax As Long
InxWshtTgtCrnt = LBound(WshtTgt)
InxWshtTgtMax = UBound(WshtTgt)
Do While InxWshtTgtCrnt <= InxWshtTgtMax
Found = False
For InxWshtActCrnt = 1 To Worksheets.Count
If Worksheets(InxWshtActCrnt).Name = WshtTgt(InxWshtTgtCrnt) Then
Found = True
Exit For
End If
Next
If Found Then
' Worksheet WshtTgt(InxWshtTgtCrnt) exists
InxWshtTgtCrnt = InxWshtTgtCrnt + 1
Else
' Worksheet WshtTgt(InxWshtTgtCrnt) does not exist
WshtTgt(InxWshtTgtCrnt) = WshtTgt(InxWshtTgtMax)
InxWshtTgtMax = InxWshtTgtMax - 1
End If
Loop
' Warning this code does not handle the situation
' of none of the worksheets existing
ReDim Preserve WshtTgt(LBound(WshtTgt) To InxWshtTgtMax)
End Sub
Function WorksheetExists(WshtName As String)
' Returns True is WshtName is the name of a
' worksheet within the active workbook.
Dim InxWshtCrnt As Long
For InxWshtCrnt = 1 To Worksheets.Count
If Worksheets(InxWshtCrnt).Name = WshtName Then
WorksheetExists = True
Exit Function
End If
Next
WorksheetExists = False
End Function