VBA code to protect all worksheets contingent on response - vba

To delete a name and correlating data in the same row on each sheet of my workbook, users need to highlight a name and click a button on the first worksheet. A confirmation window then pops up asking if they are sure. If they click NO, everything remains protected and works fine. If they click YES, all worksheets are unprotected, and a second confirmation window appears - If YES is clicked the second time, the data is deleted from each worksheet and everything is protected after deletion. HOWEVER, if NO is clicked the second time, I can't get my code to then protect everything prior to exiting the sub.
Any help is appreciated, as well as suggestions for resources to help be become more proficient on my own. :)
Here is the code:
Sub DeleteRow()
'this macro deletes the row for a selected patient from worksheet of selected month and all months after that
'variables
Dim PatientName As String, PatientRow As Long, w As Long
Dim pRow As Long, lRow As Long, LookUpRng As Range, answer As Long
Dim rArray() As Variant, sArray As Variant
ReDim rArray(0)
ReDim sArray(0)
With ActiveSheet
ActiveSheet.Unprotect "arafluid"
PatientName = .Range("d" & ActiveCell.Row)
PatientRow = ActiveCell.Row
.Rows(PatientRow).Interior.ColorIndex = 4
'check that user want has selected correct patient
answer = MsgBox("Do you want to permanently remove patient " & vbCr & vbCr & _
PatientName & " from ALL months in this workbook?", vbYesNo, "Confirmation")
.Rows(PatientRow).Interior.ColorIndex = -4142
If answer = vbNo Then ActiveSheet.Protect "arafluid"
If answer <> vbYes Then Exit Sub
'check that it is safe to delete rows in future sheets
For w = Worksheets.Count To ActiveSheet.Index Step -1
With Sheets(w)
Sheets(w).Unprotect "arafluid"
pRow = 0
lRow = .Range("d10").CurrentRegion.Rows.Count + 9
Set LookUpRng = .Range("d10" & ":d" & lRow)
On Error Resume Next
pRow = Application.WorksheetFunction.Match(PatientName, LookUpRng, 0) + 9
If Err.Number <> 0 Then
Trail = Trail & vbCr & " " & .Name & " Not Found!"
Else
Trail = Trail & vbCr & " " & .Name & " ok"
' add value on the end of the arrays
ReDim Preserve rArray(UBound(rArray) + 1) As Variant
ReDim Preserve sArray(UBound(sArray) + 1) As Variant
rArray(UBound(rArray)) = pRow
sArray(UBound(sArray)) = w
End If
On Error GoTo 0
End With
Next w
'check that user still wants to delete
answer = MsgBox("Once deleted, the information cannot be recovered. Click YES to permanently remove: " & vbCr & vbCr & _
PatientName & vbCr, vbYesNo, "Are you sure?")
If answer <> vbYes Then Exit Sub
If answer <> vbNo Then
For a = Worksheets.Count To ActiveSheet.Index Step -1
Sheets(a).Protect "arafluid"
Next a
End If
'delete rows for selected patient
For d = 1 To UBound(sArray)
Sheets(sArray(d)).Rows(rArray(d)).EntireRow.Delete
Next d
End With
'loop through all sheets in the workbook.
For w = 1 To Sheets.Count
Sheets(w).Protect "arafluid"
Next w
End Sub

You are exiting the Sub if the user said "no". Change these lines after the second MessageBox:
answer = MsgBox("Once deleted, the information cannot be recovered. Click YES to permanently remove: " & vbCr & vbCr & _
PatientName & vbCr, vbYesNo, "Are you sure?")
If answer = vbNo Then 'This will test if user said "No" and will protect the sheets
For a = Worksheets.Count To ActiveSheet.Index Step -1
Sheets(a).Protect "arafluid"
Next a
Exit Sub
End If
As a note, after the first MsgBox you have the same situation with two If statements for the same thing, you could simplify them as:
If answer = vbNo Then
ActiveSheet.Protect "arafluid"
Exit Sub
End If

Related

getting my range loop to disregard the header row?

I have a simple for loop that counts the amount of visible rows after an autofilter. I've done research and the consensus seems to be something like .Range.SpecialCells(xlCellTypeVisible).Rows.count - 1 should work, but it keeps counting the header row.
On Error Resume Next
termsfound = 0
For Each mycell In tgtws.Range.SpecialCells(xlCellTypeVisible).Rows.count - 1
If IsError(mycell) = False Then
termsfound = termsfound + 1
End If
Next
If termsfound > 0 Then
MsgBox "Found " & termsfound & " term(s).", vbOKOnly, "Results"
Else
TgtWS.Rows(1).EntireRow.AutoFilter
TgtWS.Range("A2").Select
MsgBox "No terms found"
End If
any idea why it's not working properly?
whole code:
Sub LOBEligibilityTermCheck()
Dim SrcWB As Workbook
Dim SrcWS As Worksheet
Dim TgtWS As Worksheet
Workbooks.Open ("M:\Final Terms.xlsx")
Workbooks.Open ("M:\daily-report.xlsx")
Set SrcWB = Workbooks("Final Terms.xlsx")
Set TgtWB = Workbooks("daily-report.xlsx")
Set SrcWS = SrcWB.Sheets("Sheet1")
Set TgtWS = TgtWB.Sheets(1)
Application.ScreenUpdating = False
If WorksheetIsOpen("Final Terms.xlsx", "Sheet1") = False Then
MsgBox "This macro requires the term file to be open prior to running." & vbNewLine & vbNewLine _
& "The file name MUST be 'Final Terms .xlsx' and the list MUST be in a worksheet (tab) titled 'Sheet1'." _
& vbNewLine & vbNewLine & "Please open the file and run the macro again.", vbOKOnly, "Error"
Exit Sub
End If
lastCell = TgtWS.Range("A" & TgtWS.Rows.Count).End(xlUp).Row + 1
TgtWS.Rows(1).EntireRow.Delete
TgtWS.Columns("E").Insert
TgtWS.Range("E1") = "Social Security Number"
TgtWS.Range("E2").FormulaR1C1 = "=IF(RC[-2]="""",RC[-1],RC[-2])& """""
TgtWS.Range("e2").AutoFill Destination:=TgtWS.Range("e2:e" & lastCell)
TgtWS.Range("e:e").Copy
TgtWS.Range("e:e").PasteSpecial xlPasteValues
TgtWS.Range("C:D").EntireColumn.Delete
TgtWS.Range("A1:A" & Range("AP" & Rows.Count).End(xlUp).Row).AutoFilter Field:=15, Criteria1:=">=" & CLng(Date - 2)
lastrowlob = LastRowIndex(TgtWS, 1)
TgtWS.Columns("D").Insert
TgtWS.Cells(1, 4) = "Unique Identifier"
TgtWS.Range(Cells(2, 4), Cells(lastrowlob, 4)).SpecialCells(xlCellTypeVisible).FormulaR1C1 = "=trim(rc[-3]&right(rc[-1],4))"
TgtWS.Columns("E").Insert
TgtWS.Cells(1, 5) = "Eligibility Lookup"
TgtWS.Range(Cells(2, 5), Cells(lastrowlob, 5)).SpecialCells(xlCellTypeVisible).FormulaR1C1 = "=IFNA(INDEX('[Final Terms.xlsx]Sheet1'!C13,MATCH(RC[-1],'[Final Terms.xlsx]Sheet1'!C13,0)),"""")"
TgtWS.Rows(1).EntireRow.AutoFilter
TgtWS.Range("E:E").Copy
TgtWS.Range("E:E").PasteSpecial xlPasteValues
TgtWS.Range("$A$1:$AO$" & lastrowlob).AutoFilter Field:=5, Criteria1:="<>", Operator:=xlAnd
TgtWS.Range("A2").Select
On Error Resume Next
termsfound = 0
For Each mycell In tgtws.Range.SpecialCells(xlCellTypeVisible).Rows.count - 1
If IsError(mycell) = False Then
termsfound = termsfound + 1
End If
Next
If termsfound > 0 Then
MsgBox "Found " & termsfound & " term(s).", vbOKOnly, "Results"
Else
TgtWS.Rows(1).EntireRow.AutoFilter
TgtWS.Range("A2").Select
MsgBox "No terms found"
End If
SrcWB.Close savechanges = False
Application.ScreenUpdating = True
End Sub
You are mixing up For and For Each. For works with numbers. For Each does exactly what is says - for each entry in the object, it will do what you want. In your situation, you can work with row numbers, but I would go for For Each. The cheap solution here is to test if it the first run and skip the action, but that's not good code. Do like this instead:
Dim TargetRange As Range
Set TargetRange = tgtws.Range.SpecialCells(xlCellTypeVisible)
Set TargetRange = TargetRange.Offset(1) ' move it down one row
Set TargetRange = TargetRange.Resize(TargetRange.Rows.Count - 1) ' make it one row shorter
For Each mycell In TargetRange
'...
Next
I have copied your range definition and put it in a variable. Then the range is moved one step down, and then resized. Put a TargetRange.Select in your code at a suitable location - it's a quick way to check the result while debugging.

VBA Code to Alert Against Expired Material Assistance

I am trying to create a popup window as soon as I open my excel file.
The excel workbook that I have has multiple sheets.
One of the sheets is titled "Inventory".
As shown in the image below, there is a column in the Inventory tab that is titled "Days Until Expiration".
I want to have my excel file display a pop up when opening the workbook. This popup will check the "Days Until Expiration" column in the "Inventory" tab and say something like "____ material" (from the 'Type' Column) "has ____" days until expiration.
This will only happen if the "Days Until Expiration" value is in between 0 and 14 days.
If the number is negative in the "Days Until Expiration" column, I want the message pop up to say "___ material has expired".
Shown below is what I have so far. I have created a workbook_open() event and this code is in my "ThisWorkbook" code tab.
I am also getting an error when I run what I have below, specifically saying:
Run-time error '13': Type mismatch
Private Sub Workbook_Open()
Application.WindowState = xlMaximized
Dim wb As Workbook
Dim ws As Worksheet
Dim rngUsed As Range, rngExpirationColumn As Range, rngCell As Range
Dim strExpirationMessage As String
Set wb = ThisWorkbook
Set ws = wb.Sheets("Inventory")
Set rngUsed = ws.UsedRange
Set rngExpirationColumn = Intersect(ws.Columns(4), rngUsed)
For Each rngCell In rngExpirationColumn.Cells
If Date - CDate(rngCell.Value2) >= 14 Then
If Len(strExpirationMessage) = 0 Then
strExpirationMessage = rngCell.Offset(0, -3).Value2 & " material has " & (Date - CDate(rngCell.Value2)) & " days left before expiration"
Else
strExpirationMessage = strExpirationMessage & Chr(13) & rngCell.Offset(0, -3).Value2 & " material has " & (Date - CDate(rngCell.Value2)) & " days left before expiration"
End If
End If
Next
MsgBox strExpirationMessage
End Sub
I'm posting this answer based on your request and with some assumptions, as follows:
You want to check the data for column "Days Until Expiration" (as per your request)
You want to grab the data from column "Type" to add on the popup (as per your request)
You want one message if the Expiration Days is between 0 and 14
You want another message if the Expiration Days is less than 0
The value on column "Days Until Expiration" is actually a number (this is an assumption, since no data was provided)
I'm assuming "Days Until Expiration" is merged into two rows (per screenshot)
I'm assuming your data is directly below the rows from your screenshot, so probably your actual data starts on Row 4
Here is the code (tested based on assumptions above, due to lack of actual data to reproduce the scenario):
Private Sub Workbook_Open()
Application.WindowState = xlMaximized
Dim ws As Worksheet
Dim strExpirationMessage As String
Dim rngExpirationCell As Range, rngTypeCell As Range
Dim lngRow As Long, lngExpirationCol As Long, lngTypeCol As Long
Set ws = ThisWorkbook.Worksheets("Inventory")
Set rngExpirationCell = ws.UsedRange.Find(What:="Days Until Expiration", LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
Set rngTypeCell = ws.UsedRange.Find(What:="Type", LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
If Not rngExpirationCell Is Nothing And Not rngTypeCell Is Nothing Then
lngExpirationCol = rngExpirationCell.Column
lngTypeCol = rngTypeCell.Column
For lngRow = rngExpirationCell.row + 2 To ws.UsedRange.Rows.Count
With ws.Cells(lngRow, lngExpirationCol)
If 0 <= .Value And .Value <= 14 Then
strExpirationMessage = strExpirationMessage & ws.Cells(lngRow, lngTypeCol).Value & " material has " & .Value & " days left before expiration" & vbCrLf
ElseIf .Value < 0 Then
strExpirationMessage = strExpirationMessage & ws.Cells(lngRow, lngTypeCol).Value & " material has expired" & vbCrLf
End If
End With
Next
strExpirationMessage = Left(strExpirationMessage, Len(strExpirationMessage) - 2) 'to remove trailing vbCrLf
MsgBox strExpirationMessage
End If
End Sub
Important Notes:
I've modified part of your logic, by eliminating some variables and using others instead.
I'm not working with range objects, but rather with specified cells
I'm performing a dynamic search for the desired Columns "Days Until Expiration" and "Type", instead of working with fixed column and with offsets, to allow you to change the columns position in future without changing the code.
I'm assuming "Days Until Expiration" is merged into two rows (per screenshot) and this is why I'm using rngExpirationCell.row + 2 in the For loop. If you have anything different than that, the code might need changes.
I hope this suits your needs. Let me know of any issues or concerns.
If this post answers your question, please Accept it by clicking on the Check mark on the left of it.
Update:
Based on the issues you found, below are two alternate solutions for the For loop that you could use. Everything else should be exactly the same. Just replace the For loop with either of the logic below and you should be good to go
Assuming you want to leave the logic once you found an Empty cell:
For lngRow = rngExpirationCell.row + 2 To ws.UsedRange.Rows.Count
With ws.Cells(lngRow, lngExpirationCol)
If IsEmpty(.Value) Then Exit For 'Will leave the For loop once an Empty cell is found
If 0 <= .Value And .Value <= 14 Then
strExpirationMessage = strExpirationMessage & ws.Cells(lngRow, lngTypeCol).Value & " material has " & .Value & " days left before expiration" & vbCrLf
ElseIf .Value < 0 Then
strExpirationMessage = strExpirationMessage & ws.Cells(lngRow, lngTypeCol).Value & " material has expired" & vbCrLf
End If
End With
Next
Assuming you want to skip the evaluation for the Empty cells, but continue checking the cells until the end of the Used Range:
For lngRow = rngExpirationCell.row + 2 To ws.UsedRange.Rows.Count
With ws.Cells(lngRow, lngExpirationCol)
If Not IsEmpty(.Value) Then 'Will skip empty cells but continuing validation until the end of the Used Range
If 0 <= .Value And .Value <= 14 Then
strExpirationMessage = strExpirationMessage & ws.Cells(lngRow, lngTypeCol).Value & " material has " & .Value & " days left before expiration" & vbCrLf
ElseIf .Value < 0 Then
strExpirationMessage = strExpirationMessage & ws.Cells(lngRow, lngTypeCol).Value & " material has expired" & vbCrLf
End If
End If
End With
Next

VBA to delete entire row based on cell value

I'm experiencing some issues getting the provided VBA code working and would appreciate any assistance.
I have two Workbooks (1) is a monthly report I receive that has multiple worksheets, Worksheet "host_scan_data" contains the source of the information I will need to work with. The other Workbook (2) is where I will store all consolidated date month over month.
How I'm trying to accomplish this task:
1. launch workbook #2
2. click a button that has the following VBA code assigned to (see below)
3. browse and select my monthly report (workbook #1)
4. specify the worksheet tab in workbook #2 where i'd like to store this consolidate information
5. prompt user to validate worksheet tab where data will be stored
Based on the responses above the macro will then analyze Column K within the "host_scan_data" Sheet of the Workbook (1), and I would like for it to remove all rows where Column k contains a "0" (note the only values i'm concerned about are 4,3,2,1). Once that action is complete i'd like for the macro to copy the consolidated list of entry's over to the location specified in step #4 above.
I've tried this with a few variations of code and other solutions appear to work fine when the "host_scan_data" Sheet contains <4,000 rows however once I exceed that number (give or take) excel becomes unresponsive. Ideally this solution will need to handle approx 150,000+ rows.
Here is the code i'm currently using, when i execute it errors out at ".Sort .Columns(cl + 1), Header:=xlYes":
The Code I Have so far:
Sub Import()
Dim strAnswer
Dim itAnswer As String
Dim OpenFileName As String
Dim wb As Workbook
Dim db As Workbook
Dim Avals As Variant, X As Variant
Dim i As Long, LR As Long
'Optimize Code
Call OptimizeCode_Begin
'Select and Open workbook
OpenFileName = Application.GetOpenFilename("*.xlsx,")
If OpenFileName = "False" Then Exit Sub
Set wb = Workbooks.Open(OpenFileName, UpdateLinks:=0)
Set db = ThisWorkbook
'Provide Sheet Input
strAnswer = InputBox("Please enter name of worksheet where Nessus data will be imported:", "Import Name")
If strAnswer = "" Then
MsgBox "You must enter a valid name. Exiting now..."
wb.Close
Exit Sub
Else
Response = MsgBox(strAnswer, vbYesNo + vbCritical + vbDefaultButton2, "Is this Correct?")
If Response = vbNo Then
MsgBox "Got it, you made a mistake. Exiting now..."
wb.Close
Exit Sub
Else: MsgBox "Importing Now!"
End If
End If
wb.Sheets("host_scan_data").Activate
Dim rs, cl, Q()
Dim arr1, j, C, s As Long
Dim t As String: t = "4"
Dim u As String: u = "3"
Dim v As String: v = "2"
Dim w As String: w = "1"
If Cells(1) = "" Then Cells(1) = Chr(2)
'Application.Calculation = xlManual
rs = wb.Sheets("host_scan_data").Cells.Find("*", , , , , xlByRows, xlPrevious).Row
cl = wb.Sheets("host_scan_data").Cells.Find("*", , , , , xlByColumns, xlPrevious).Column
ReDim Q(1 To rs, 1 To 1)
arr1 = wb.Sheets("host_scan_data").Cells(1, "k").Resize(rs)
For j = 1 To rs
C = arr1(j, 1)
If (C <> t) * (C <> u) * (C <> v) * (C <> w) Then Q(j, 1) = 1: s = s + 1
Next j
If s > 0 Then
With Cells(1).Resize(rs, cl + 1)
.Columns(cl + 1) = Q
.Sort .Columns(cl + 1), Header:=xlYes
.Cells(cl + 1).Resize(s).EntireRow.Delete
End With
End If
countNum = (Application.CountA(Range("B:B"))) - 1
MsgBox (countNum & " Rows being imported now!")
countNum = countNum + 2
db.Sheets(strAnswer).Range("A3:A" & countNum).value = wb.Sheets("host_scan_data").Range("B3:B" & countNum).value
db.Sheets(strAnswer).Range("B3:B" & countNum).value = wb.Sheets("host_scan_data").Range("K3:K" & countNum).value
db.Sheets(strAnswer).Range("C3:C" & countNum).value = wb.Sheets("host_scan_data").Range("H3:H" & countNum).value
db.Sheets(strAnswer).Range("D3:D" & countNum).value = wb.Sheets("host_scan_data").Range("M3:M" & countNum).value
db.Sheets(strAnswer).Range("E3:E" & countNum).value = wb.Sheets("host_scan_data").Range("L3:L" & countNum).value
db.Sheets(strAnswer).Range("F3:F" & countNum).value = wb.Sheets("host_scan_data").Range("O3:O" & countNum).value
db.Sheets(strAnswer).Range("G3:G" & countNum).value = wb.Sheets("host_scan_data").Range("G3:G" & countNum).value
db.Sheets(strAnswer).Range("K3:K" & countNum).value = wb.Sheets("host_scan_data").Range("X3:X" & countNum).value
MsgBox ("Done")
'Close nessus file
wb.Close SaveChanges:=False
'Else
'MsgBox "You must enter 1 or 2 only. Exiting now..."
'wb.Close
'Exit Sub
'End If
Sheets(strAnswer).Select
'Optimize Code
Call OptimizeCode_End
End Sub
So here is what may be happening.
If the row you are deleting has data used, in a formula somewhere else, that formula is going to recalculate on every iteration of the row delete.
I had this problem with a data set which has many Vlookup functions pulling data.
here is what I did and it take a few seconds rather than 30min
Sub removeLines()
Dim i As Long
Dim celltxt As String
Dim EOF As Boolean
Dim rangesize As Long
EOF = False
i = 1
'My data has "End of File" at the end so I check for that
' Though it would be better to used usedRange
While Not (EOF)
celltxt = ActiveSheet.Cells(i, 1).Text
If InStr(1, celltxt, "end", VbCompareMethod.vbTextCompare) > 0 Then
EOF = True 'if we reach the "end Of file" then exit
' so I clear a cell that has no influence on any functions thus
' it executes quickly
ElseIf InStr(1, celltxt, "J") <> 1 Then
Cells(i, 1).Clear
End If
i = i + 1
Wend
' once all the rows to be deleted are marked with the cleared cell
' I use the specialCells to select and delete all the rows at once
' so that the dependent formula are only recalculated once
Columns("A:A").Select
Selection.SpecialCells(xlCellTypeBlanks).Select
Selection.EntireRow.Delete
End Sub
hope this helps and that it is read able
I tried a little different approach by using AutoFilter and i'm seeing a high success rate on my larger lists however there still is one issue. With the code below i was able to parse through 67k+ rows and filter/delete any row contains a "0" in my column K (this takes approx 276 seconds to complete), after the code filters and deletes the rows with zeros it clears any existing filters then is to copy the remaining data into my Workbook #2 (this is approx 7k rows) however it is consistently only copying 17 rows of data into my workbook #2, it just seems to stops and i have no idea why. Also, while 4.5 mins to complete the consolidation could be acceptable does anyone have any ideas on how to speed this up?
Sub Import()
Dim strAnswer
Dim itAnswer As String
Dim OpenFileName As String
Dim wb As Workbook
Dim db As Workbook
Dim Avals As Variant, X As Variant
Dim i As Long
Dim FileLastRow As Long
Dim t As Single
Dim SevRng As Range
t = Timer
'Optimize Code
Call OptimizeCode_Begin
'Select and Open workbook
OpenFileName = Application.GetOpenFilename("*.xlsx,")
If OpenFileName = "False" Then Exit Sub
Set wb = Workbooks.Open(OpenFileName, UpdateLinks:=0)
Set db = ThisWorkbook
'Provide Sheet Input
strAnswer = InputBox("Please enter name of worksheet where Nessus data will be imported:", "Import Name")
If strAnswer = "" Then
MsgBox "You must enter a valid name. Exiting now..."
wb.Close
Exit Sub
Else
Response = MsgBox(strAnswer, vbYesNo + vbCritical + vbDefaultButton2, "Is this Correct?")
If Response = vbNo Then
MsgBox "Got it, you made a mistake. Exiting now..."
wb.Close
Exit Sub
Else: MsgBox "Importing Now!"
End If
End If
FileLastRow = wb.Sheets("host_scan_data").Range("K" & Rows.Count).End(xlUp).Row
Set SevRng = wb.Sheets("host_scan_data").Range("K2:K" & FileLastRow)
Application.DisplayAlerts = False
With SevRng
.AutoFilter Field:=11, Criteria1:="0"
.Offset(1, 0).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).Rows.Delete
.Cells.AutoFilter
End With
Application.DisplayAlerts = True
MsgBox "Consolidated in " & Timer - t & " seconds."
countNum = (Application.CountA(Range("B:B"))) - 1
MsgBox (countNum & " Rows being imported now!")
countNum = countNum + 2
db.Sheets(strAnswer).Range("A3:A" & countNum).value = wb.Sheets("host_scan_data").Range("B3:B" & countNum).value
db.Sheets(strAnswer).Range("B3:B" & countNum).value = wb.Sheets("host_scan_data").Range("K3:K" & countNum).value
db.Sheets(strAnswer).Range("C3:C" & countNum).value = wb.Sheets("host_scan_data").Range("H3:H" & countNum).value
db.Sheets(strAnswer).Range("D3:D" & countNum).value = wb.Sheets("host_scan_data").Range("M3:M" & countNum).value
db.Sheets(strAnswer).Range("E3:E" & countNum).value = wb.Sheets("host_scan_data").Range("L3:L" & countNum).value
db.Sheets(strAnswer).Range("F3:F" & countNum).value = wb.Sheets("host_scan_data").Range("O3:O" & countNum).value
db.Sheets(strAnswer).Range("G3:G" & countNum).value = wb.Sheets("host_scan_data").Range("G3:G" & countNum).value
db.Sheets(strAnswer).Range("K3:K" & countNum).value = wb.Sheets("host_scan_data").Range("X3:X" & countNum).value
MsgBox ("Done")
'Close nessus file
wb.Close SaveChanges:=False
Sheets(strAnswer).Select
'Optimize Code
Call OptimizeCode_End
End Sub
Does your
"MsgBox (countNum & " Rows being imported now!")"
return the correct number of rows?
CountA will stop counting at the first empty cell.
Try instread:
countNum = ActiveSheet.UsedRange.Rows.Count

Excel VBA: message box to show list of errors at the end

I am new to VBA and I would really appreciate your help with the following. The code below searchers for blanks in Column A, highlights them, then it shows a message every time a cell has blanks with the cell location (e.g."No Value, in $A$1"). I copy these cells locations in another tab called "Results".
I need help with the following. I want to somehow for the message to show once with the list of cells that have blanks and their location. I do not want the message to pop out every time it finds a blank cell (I could have hundreds of blank cells in a file and clicking Ok for each one is not practical). Then that list of values will be copied in my "Results" sheet.
Here is the code I currently have:
Sub CeldasinInfo()
Dim i As Long, r As Range, coltoSearch As String
coltoSearch = "A"
For i = 1 To Range(coltoSearch & Rows.Count).End(xlUp).Row
Set r = Range(coltoSearch & i)
If Len(r.Value) = 0 Then
r.Interior.ColorIndex = 3 ' Red
r.Select
MsgBox "No Value, in " & r.Address
Sheets("Results").Range("A" & Sheets("Results").Range("A" & Rows.Count).End(xlUp).Row).Offset(1, 0).Formula = r.Address
End If
Next
End Sub
Thank so much in advance. I would really appreciate your help with this.
Something like this should work for you:
Sub CeldasinInfo()
Dim i As Long, r As Range, coltoSearch As String
Dim Result as String
Dim ErrCount as integer
ErrCount = 0
coltoSearch = "A"
coltoSearch = Range("1:1").find(What:="Hours", LookIn:=xlValues, LookAt:=xlWhole).Column
Result = "No Value in:" & vbcrlf
For i = 1 To Range(coltoSearch & Rows.Count).End(xlUp).Row
Set r = Range(coltoSearch & i)
If Len(r.Value) = 0 Then
r.Interior.ColorIndex = 3 ' Red
r.Select
' MsgBox "No Value, in " & r.Address
Result = Result & r.Address & vbcrlf
ErrCount = ErrCount + 1
if ErrCount Mod 10 = 0 then 'change to 15 or 20 or whatever works well
MsgBox Result
Result = "No Value in:" & vbcrlf
End If
Sheets("Results").Range("A" & Sheets("Results").Range("A" & Rows.Count).End(xlUp).Row).Offset(1, 0).Formula = r.Address
End If
Next
If ErrCount > 0 then
MsgBox "There were " & ErrCount & " errors detected." & vbcrlf & result
else
MsgBox "No errors detected"
End If
End Sub
This will give you each address on a separate line in the MsgBox. If there are hundreds of errors likely, this will result in a very long MsgBox output, and I'm not sure how it will handle that. You may need to add in a counter and display the message every 10, 15 or 20 errors for a better looking output.
If your cells are truly blank you can avoid a range loop and use SpecialCells
Sub CeldasinInfo()
Dim rng1 As Range
Dim coltoSearch As String
coltoSearch = "A"
On Error Resume Next
Set rng1 = Columns(coltoSearch).SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If rng1 Is Nothing Then Exit Sub
rng1.Interior.ColorIndex = 3 ' Red
MsgBox "No Value, in " & rng1.Address
End Sub

Changing invoice number automatically on workbook close but checking if it has to increase or not

I have this code below for my workbook that saves the workbook for me and also increases the invoice number by 1 based on the value in a certain cell:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Range("L5").Value = Range("L5").Value + 1
ThisWorkbook.Save
End Sub
So cell L5 starts with 1 and right now everytime the workbook is closed it will add +1 to it and save the book, so the next time it opens it will be 2,3,4,5 and so on.
The problem I have is that if someone closes it and open and closes it will keep adding numbers even though that invoice doesn't exit.
Is there anyway it can check a list of value from a column in sheet 2 to see if the current invoice number exists, if it does then add 1 and save, if not then leave the same number and save?
UPDATED SUBMIT CODE WITH CLEARING, SAVING, AND UPDAING INVOCE NUMBER. All cells are locked and protected except the cells in the refTable, those are editable by user but L5 is locked and needs to be editable by the VBA code only, not users.
Sub Submit()
Dim refTable As Variant, trans As Variant
refTable = Array("B = L5", "C = C5", "D=G5", "E=C10", "F=C9", "G=I9", "H=I10", "I=C13", "J=C14", "K=C15", "L=C16", "M=C17", "N=C18", "O=I13", "P=I14", "Q=I15", "R=I16", "S=I17", "W=H20")
Dim Row As Long
Row = Worksheets("TravelLog").UsedRange.Rows.Count + 1
For Each trans In refTable
Dim Dest As String, Field As String
Dest = Trim(Left(trans, InStr(1, trans, "=") - 1)) & Row
Field = Trim(Right(trans, Len(trans) - InStr(1, trans, "=")))
Worksheets("TravelLog").Range(Dest).Value = Worksheets("TravelRequest").Range(Field).Value
Next
If Worksheets("TravelRequest").CheckBox1.Value Then
Worksheets("TravelLog").Range("T" & Row).Value = "Yes"
Else
Worksheets("TravelLog").Range("T" & Row).Value = "No"
End If
If Worksheets("TravelRequest").CheckBox2.Value Then
Worksheets("TravelLog").Range("U" & Row).Value = "Yes"
Else
Worksheets("TravelLog").Range("U" & Row).Value = "No"
End If
If Worksheets("TravelRequest").CheckBox3.Value Then
Worksheets("TravelLog").Range("V" & Row).Value = "Yes"
Else
Worksheets("TravelLog").Range("V" & Row).Value = "No"
End If
Range("L5").Value = Range("L5").Value + 1
Range("I9:I10, I13:I17, H20, C5, C9:C10, C13:C18").Select
Selection.ClearContents
Dim OleObj As OLEObject
For Each OleObj In ActiveSheet.OLEObjects
If OleObj.progID = "Forms.CheckBox.1" Then
OleObj.Object = False
End If
Next OleObj
ThisWorkbook.Save
End Sub
Use goto in Workbook_BeforeClose with condition u mentioned like that
Private Sub Workbook_BeforeClose(Cancel As Boolean)
If 'your_condition' = TRUE Then goto do_save
Range("L5").Value = Range("L5").Value + 1
do_save:
ThisWorkbook.Save
End Sub