VBA: validating no empty cells in ranges before proceeding - vba

I have three ranges in a sheet (rng1, rng2, rng3) where I need to make sure that rng2 and rng3 contain no blanks before proceeding with the macro.
I have tried several methods that I can find and cannot get any of them to work. Willing to try a different method if someone has suggestions.
This is me trying to count blank cells using specialcells(xlCellTypeBLanks) but something isn't working with my error handling when neither range is blank:
Dim wrk As Workbook
Dim sht As Worksheet
Dim twb As Workbook
Dim tws As Worksheet
Dim lrow As Long
Dim rng1 As Range
Dim rng2 As Range
Dim rng3 As Range
Dim finprod As Variant
Dim subprod As Variant
Application.ScreenUpdating = False
Set wrk = ActiveWorkbook
Set sht = wrk.Worksheets(1)
For Each sht In wrk.Worksheets
lrow = sht.Range("A" & Rows.Count).End(xlUp).Row
Set rng1 = sht.Range("A2:A" & lrow)
Set rng2 = sht.Range("F2:F" & lrow)
Set rng3 = sht.Range("E2:E" & lrow)
On Error GoTo Err1
If rng3.SpecialCells(xlCellTypeBlanks).Count > 0 Then
MsgBox ("Invalid item number.")
Exit Sub
End If
Err1:
On Error GoTo Err2
If rng2.SpecialCells(xlCellTypeBlanks).Count > 0 Then
MsgBox ("Missing quantity.")
Exit Sub
End If
Err2:
On Error GoTo 0
Exit For
Next sht

I try to avoid using goto in such way - it makes the code confusing when it gets bigger. Here is what I came up with:
Sub check_blank()
Dim sht As Worksheet
Dim twb As Workbook
Dim tws As Worksheet
Dim lrow As Long
Dim rng1 As Range
Dim rng2 As Range
Dim rng3 As Range
Dim finprod As Variant
Dim subprod As Variant
Application.ScreenUpdating = False
Set wrk = ActiveWorkbook
Set sht = wrk.Worksheets(1)
For Each sht In wrk.Worksheets
lrow = sht.Range("A" & Rows.Count).End(xlUp).Row
Set rng1 = sht.Range("A2:A" & lrow)
Set rng2 = sht.Range("F2:F" & lrow)
Set rng3 = sht.Range("E2:E" & lrow)
If Application.CountIf(rng3, "") > 0 Then
MsgBox ("Invalid item number.")
Exit Sub
End If
If Application.CountIf(rng2, "") > 0 Then
MsgBox ("Missing quantity.")
Exit Sub
End If
Next sht
End Sub

The Range.SpecialCells method is Nothing when there are no xlCellTypeBlanks cells available and Nothing does not have a count; not even a count of zero.
You can use the On Error Resume Next or choose a non-destructive method of determining if there are blank cells.
if cbool(application.countblank(rng2)) then
'there are zero-length string and/or blank cells
'do something
end if
The problem with the above is that the worksheet's COUNTBLANK function will count zero-length strings returned by a formula (e.g. "") as blanks when they are not truly blank.
To catch only truly blank cells the following will be True - CBool(rng2.Count - application.Countif(rng2, "<>")). Only truly blank cells will be counted and any non-zero count will be true. This avoids having to crash the environment with On Error Resume Next when there is nothing to find.

Related

How can I search for a string in multiple Wksheets simultaneously?

I have around 30 sheets that I want this code to run in at the same time. I want to find "ABC" and delete the value of the cell next to it in all my worksheets.
I get my error from: Set rSearch = .**range**("A1", .range("A" & rows.count).end(x1up))
When I have specified "Sheet1" next to the "With" statement, it works, but I want this code to run on all my sheets.
Sub soek()
Dim rSearch As Range
Dim rFound As Range
Dim sign12 As String
Dim sheetsarray As Sheets
Set sheetsarray = ActiveWorkbook.Sheets(Array("sheet1", "sheet2", "sheet3"))
sign12 = "ABC"
With sheetsarray
Set rSearch = .Range("A1", .Range("A" & Rows.Count).End(xlUp))
Set rFound = rSearch.Find(What:=sign12, LookIn:=xlValues)
If rFound Is Nothing Then
Else
rFound.Offset(0, 1).ClearContents
End If
End With
End Sub
This question is a lot like: How to search for a string in all sheets of an Excel workbook?
But in my opinion, it's a lot easier to understand how to make code run on additional sheets reading my code than the code from the link above.
Try this (compilation of the comments above ;-)
Sub soek()
Dim rSearch As Range
Dim rFound As Range
Dim sign12 As String
Dim oWB As Workbook
Dim oWS As Worksheet
Set oWB = ThisWorkbook
sign12 = "ABC"
For Each oWS In oWB.Sheets
With oWS
Set rSearch = .Range("A1", .Range("A" & Rows.Count).End(xlUp))
Set rFound = rSearch.Find(What:=sign12, LookIn:=xlValues)
If rFound Is Nothing Then
Else
rFound.Offset(0, 1).ClearContents
End If
End With
Next oWS
End Sub

VBA to loop through worksheets running code either doesnt loop or does loop but doesnt run code

I am trying to cycle through all worksheets apart from one called 'summary', looking down a range in column A until finding a value, then looking in another workbook and getting some data, pasting it in, then carrying on until the end of column A range. Then it should move onto the next worksheet and repeat the process. I have been able to execute the code within the loop successfully, but only on the active worksheet. I've tried various iterations of the 'for each' statements. The current way seems to loop through the worksheets but doesn't run the code.
How can i amend it so it works properly?
Sub GetFlows()
Dim rng As Range
Dim row As Range
Dim cell As Range
Dim dem1 As String
Dim WhereCell As Range
Dim ws As Excel.Worksheet
Dim iIndex As Integer
Dim valueRng As Range
Dim x As Long
Dim y As Long
Set rng = Range("A9:A200")
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "summary" Then
ws.Activate
For x = 1 To rng.Rows.Count
dem1 = rng.Cells(x).Value
If dem1 <> "" Then
Set WhereCell = ThisWorkbook.ActiveSheet.Range("A9:A200").Find(dem1, lookat:=xlPart)
Windows("GetFilenames v2.xlsm").Activate
Worksheets(dem1).Range("A1").CurrentRegion.Copy
WhereCell.Offset(, 2).PasteSpecial Paste:=xlPasteValues
Else
ThisWorkbook.Activate
End If
Next x
End If
Next ws
End Sub
You could avoid all the Activate and Select and qualify all your Range and Cells statemets inside by using With ws.
So after you loop through all your Worksheets in :
For Each ws In ThisWorkbook.Worksheets , you add With ws and all the objects inside are qualified with the ws object.
Code:
Option Explicit
Sub GetFlows()
Dim cell As Range
Dim dem1 As String
Dim WhereCell As Range
Dim ws As Worksheet
Dim valueRng As Range
Dim x As Long
Dim y As Long
For Each ws In ThisWorkbook.Worksheets
With ws
If .Name <> "summary" Then
For x = 9 To 200 ' run a loop from row 9 to 200
dem1 = .Range("A" & x).Value
If dem1 <> "" Then
Set WhereCell = .Range("A9:A200").Find(what:=dem1, LookAt:=xlPart)
If Not WhereCell Is Nothing Then
Workbooks("GetFilenames v2.xlsm").Worksheets(dem1).Range("A1").CurrentRegion.Copy
WhereCell.Offset(, 2).PasteSpecial xlPasteValues
End If
End If
Next x
End If
End With
Next ws
End Sub
Can you try this? This checks if the value is found.
Sub GetFlows()
Dim rng As Range
Dim row As Range
Dim cell As Range
Dim dem1 As String
Dim WhereCell As Range
Dim ws As Excel.Worksheet
Dim iIndex As Integer
Dim valueRng As Range
Dim x As Long
Dim y As Long
Set rng = Range("A9:A200") ' should specify a sheet here, presumably Summary?
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "summary" Then
For x = 1 To rng.Rows.Count
dem1 = rng.Cells(x).Value
If dem1 <> vbNullString Then
Set WhereCell = ws.Range("A9:A200").Find(dem1, lookat:=xlPart)
If Not WhereCell Is Nothing Then
Workbooks("GetFilenames v2.xlsm").Worksheets(dem1).Range("A1").CurrentRegion.Copy
WhereCell.Offset(, 2).PasteSpecial Paste:=xlPasteValues
End If
End If
Next x
End If
Next ws
End Sub

VBA - Check blank cells - Wrong output

I have a code that checks in a range if some cells are blank (empty or not). It gives me a message saying so. But, it seems not working well : the output message always says that there are some empty cells in the range (column A to H, until the last populated row) whereas it's the contrary (always data).
I precise that the layout of the range is a table! MsgBox(LastRow) is every time equal to the last row also..
Here is a part of the code:
Set sht = ThisWorkbook.Worksheets("SS upload")
Set StartCell = Range("A14")
LastRow = sht.Cells(sht.Rows.Count, StartCell.Column).End(xlUp).Row
MsgBox (LastRow)
Set Rrng = Range("A14 : H" & LastRow)
For Each cell In Rrng
If IsEmpty(cell) = True Then
bIsEmpty = True
Exit For
End If
Next cell
If bIsEmpty = True Then
MsgBox "There are empty cells in the file"
Else
MsgBox "All cells have values!"
End If
End Sub
Does anything seem wrong in this?
Thank you for your precious help! :)
Regards
Probably you are not realizing, that you are looking in a range(A14:H LAST Row) Thus, if you have 5 rows, then the range is still Range(A14:H5). And there, you have empty values.
Public Sub TestME()
Dim bIsEmpty As Boolean
Set sht = ThisWorkbook.Worksheets(2)
Set StartCell = Range("A14")
LastRow = sht.Cells(sht.Rows.Count, StartCell.Column).End(xlUp).row
MsgBox (LastRow)
Set Rrng = Range("A1 : H" & LastRow)
For Each cell In Rrng
If IsEmpty(cell) = True Then
bIsEmpty = True
Exit For
End If
Next cell
If bIsEmpty Then
MsgBox "There are empty cells in the file"
Else
MsgBox "All cells have values!"
End If
End Sub
That's strange indeed because it also work sometimes. I mean the output message "All cells have value" is conformed to what's really in the file (no blanks at all) but sometimes not..
Here is my full code:
Sub empty_cells()
Dim sht As Worksheet
Dim Rrng As Range
Dim cell As Range
Dim LastRow As Long
Dim StartCell As Range
Dim bIsEmpty As Boolean
Set sht = ThisWorkbook.Worksheets("SS upload")
Set StartCell = Range("A14")
LastRow = sht.Cells(sht.Rows.Count, StartCell.Column).End(xlUp).Row
MsgBox (LastRow)
Set Rrng = Range("A14 : H" & LastRow)
For Each cell In Rrng
If IsEmpty(cell) = True Then
bIsEmpty = True
Exit For
End If
Next cell
If bIsEmpty = True Then
MsgBox "There are empty cells in the file"
Else
MsgBox "All cells have values!"
End If
End Sub
thanks for your support :)

select multi range with .find, .findnext variable (copies EMPTY cells)

I'm struggling with the following code which you can see below. It is totally a pain in the *** now. I really need some help.
This code is a search tool which looks for criteria from every worksheet except the summary and the list. After the .Find founds the word, then the code selects a 4 wide range around the searched word, then it copies and pastes it on the Summary sheet.
When the first searched word is found, I also would like to copy and paste the actual worksheet (where the word is found) title (on each worksheet "G3:J3") right after the search result on the summary page. This search tool could help me to find quickly which search criteria where can be found, at which sheet and some properties which also inside the title.
The result should look like this: (r1 = the first 4 columns, r2= the rest 4 columns (that is the excel header))
item nr. Item Owner Used Capacity ESD_nr. box Owner Free capacity location
Sorry for the long description.
CODE:
Private Sub searchTool()
Dim ws As Worksheet, OutputWs As Worksheet, wbName As Worksheet
Dim rFound As Range, r1 As Range, r2 As Range, multiRange As Range
Dim strName As String
Dim count As Long, lastRow As Long
Dim IsValueFound As Boolean
IsValueFound = False
Set OutputWs = Worksheets("Summary") '---->change the sheet name as required
lastRow = OutputWs.Cells(Rows.count, "K").End(xlUp).Row
On Error Resume Next
strName = ComboBox1.Value
If strName = "" Then Exit Sub
For Each ws In Worksheets
If ws.Name <> "lists" And ws.Name <> "Summary" Then
With ws.UsedRange
Set rFound = .Find(What:=strName, LookIn:=xlValues, LookAt:=xlWhole)
If Not rFound Is Nothing Then
firstAddress = rFound.Address
Do
IsValueFound = True
Set r1 = Range(rFound.EntireRow.Cells(1, "B"), rFound.EntireRow.Cells(1, "D"))
Set r2 = Range("G3:J3")
Set multiRange = Application.Union(r1, r2)
multiRange.Copy
OutputWs.Cells(lastRow + 1, 11).PasteSpecial xlPasteAll
Application.CutCopyMode = False
lastRow = lastRow + 1
Set rFound = .FindNext(rFound)
Loop While Not rFound Is Nothing And rFound.Address <> firstAddress
End If
End With
End If
Next ws
On Error GoTo 0
If IsValueFound Then
OutputWs.Select
MsgBox "Seach complete!"
Else
MsgBox "Name not found!"
End If
End Sub
I must admit I had trouble following your requirements and there was not a definition of where it wasn't working, to that end I re-wrote it to help me understand.
Private Sub SearchTool_2()
Dim BlnFound As Boolean
Dim LngRow As Long
Dim RngFind As Excel.Range
Dim RngFirstFind As Excel.Range
Dim StrName As String
Dim WkShtOutput As Excel.Worksheet
Dim WkSht As Excel.Worksheet
StrName = "Hello" 'ComboBox1.Value
If StrName = "" Then Exit Sub
Set WkShtOutput = ThisWorkbook.Worksheets("Summary")
LngRow = WkShtOutput.Cells(WkShtOutput.Rows.count, "K").End(xlUp).Row + 1
For Each WkSht In ThisWorkbook.Worksheets
If (WkSht.Name <> "lists") And (WkSht.Name <> "Summary") Then
With WkSht.UsedRange
Set RngFind = .Find(What:=StrName, LookIn:=xlValues, LookAt:=xlWhole)
If Not RngFind Is Nothing Then
Set RngFirstFind = RngFind
BlnFound = True
Do
WkSht.Range(RngFind.Address & ":" & WkSht.Cells(RngFind.Row, RngFind.Column + 2).Address).Copy WkShtOutput.Range(WkShtOutput.Cells(LngRow, 11).Address)
WkSht.Range("G3:J3").Copy WkShtOutput.Range(WkShtOutput.Cells(LngRow + 1, 11).Address)
LngRow = LngRow + 2
Set RngFind = .FindNext(RngFind)
Loop Until RngFind.Address = RngFirstFind.Address
End If
End With
End If
Next
Set WkShtOutput = Nothing
If BlnFound Then
ThisWorkbook.Worksheets("Summary").Select
MsgBox "Seach complete!"
Else
MsgBox "Name not found!"
End If
End Sub
I found the copy statement was the better option rather than using the clipboard, I also found a missing reference of firstAddress.

VBA: looping through worksheets using nested For Each having worksheet as variable

Newbie at vba here. I'm trying to apply a simple For Each loop (which nullifies cells < 0) to all worksheets in the workbook by nesting this inside another For Each loop.
When I try and run my code below I get an error and I'm not sure if it has anything to do with having worksheet as a variable within a Set statement.
Can't seem to figure this out/find a solution.
Thanks
Sub deleteNegativeValue()
Application.DisplayAlerts = False
Dim lastRow As Long
Dim ws As Worksheet
Dim cell As Range
Dim res As Range
For Each ws In Workbooks(1).Worksheets
Set res = ws.Range("1:1").Find("Value", lookat:=xlPart)
lastRow = ws.Range("A" & Rows.Count).End(xlUp).Row
For Each cell In Range(ws.Cells(1, res.Column), ws.Cells(lastRow, res.Column))
If cell < 0 Then cell = ""
Next
Next
End Sub
Try this:
Sub deleteNegativeValue()
Dim lastRow As Long
Dim ws As Worksheet
Dim cell As Range
Dim res As Range
For Each ws In ThisWorkbook.Worksheets
Set res = ws.Range("1:1").Find("Value", lookat:=xlPart)
lastRow = ws.Range("A" & Rows.Count).End(xlUp).row
If Not res Is Nothing Then
For Each cell In ws.Range(ws.Cells(1, res.Column), ws.Cells(lastRow, res.Column))
If cell < 0 Then cell = ""
Next
Else
MsgBox "No Value found on Sheet " & ws.Name
End If
Next
End Sub
There needs to be a check on the Find method, to ensure that something was found
you could try this
Option Explicit
Sub deleteNegativeValue()
Dim ws As Worksheet
Dim res As Range
For Each ws In ThisWorkbook.Worksheets
Set res = Intersect(ws.Rows(1), ws.UsedRange).Find("value", LookAt:=xlPart)
If Not res Is Nothing Then
ws.Columns(res.Column).SpecialCells(xlCellTypeConstants, xlNumbers).Replace What:="-*", Replacement:="", SearchOrder:=xlByColumns, MatchCase:=False, LookAt:=xlWhole
Else
MsgBox "No Value found on Sheet " & ws.Name
End If
Next
End Sub
which should run faster since it doesn't iterate through every cell of each column and restrict the Find method range to the used one instead of the entire row.
the only warning is that the first row of all searched in sheets must not be empty...
Try the second for-each this way:
ws.Range(ws.Cells(1, res.Column), ws.Cells(lastRow, res.Column))