Im trying to write / find a macro that when ran removes the value in a cell if the cells in the column is not a number. IE remove all the cells in column B if a string is found. I have this script to delete empty rows.
Was just trying to re write it so that it can delete the rows based on these condiitions
Sub RemoveRows()
Dim lastrow As Long
Dim ISEmpty As Long
lastrow = Application.CountA(Range("A:XFD"))
Range("A1").Select
Do While ActiveCell.Row < lastrow
ISEmpty = Application.CountA(ActiveCell.EntireRow)
If ISEmpty = 0 Then
ActiveCell.EntireRow.Delete
Else
ActiveCell.Offset(1, 0).Select
End If
Loop
End Sub
The code iterates backward from the last cell in column B and checks if the value in the cell is numeric using the IsNumeric() function.
If the value is not numeric then it deletes the entire row.
Note: looping backwards (ie. from the last row to first) is necessary when using a loop because the index gets shifted everytime a row gets deleted. Therefore, to avoid skipping some rows backward iteration is required.
Sub KeepOnlyNumbers()
Application.ScreenUpdating = False
Dim ws As Worksheet
Set ws = Sheets("Sheet1")
Dim i As Long
' iterating backwards (from last row to first to keep the logic flow)
For i = ws.Range("B" & ws.Rows.Count).End(xlUp).Row To 1 Step -1
' check whether the value is numeric
If Not IsNumeric(Range("B" & i)) Then
' if not numeric then clear the cells content
Range("B" & i).ClearContents
End If
Next i
Application.ScreenUpdating = True
End Sub
You can use IsNumeric to evaluate if an object can be evaluated as a number. So you can add:
If Not IsNumeric(ActiveCell) Then
ActiveCell.EntireRow.Delete
Else
ActiveCell.Offset(1, 0).Select
End If
to your Do While loop and it should do what you want. I haven't tested this; let me know if you get an error.
You do not have to iterate backwards even when deleting rows, you can do union and call delete/clear on the unioned range.
Sub UnionOnCondition()
Dim usedColumnB
Set usedColumnB = Intersect(ActiveSheet.UsedRange, _
ActiveSheet.Columns("b"))
If usedColumnB Is Nothing Then _
Exit Sub
Dim result: Set result = Nothing
Dim cellObject
For Each cellObject In usedColumnB
' skip blanks, formulas, dates, numbers
If cellObject = "" Or _
cellObject.HasFormula Or _
IsDate(cellObject) Or _
IsNumeric(cellObject) Then GoTo continue
If result Is Nothing Then
Set result = cellObject.EntireRow
Else
Set result = Union(result, cellObject.EntireRow)
End If
continue:
Next
If Not result Is Nothing Then _
result.Select ' result.Clear or result.Delete
End Sub
Related
I've made a For Each loop that'll keep data depending upon some criteria's, but I do not know how to format it so if a cell in column A contain exactly 8 numeric digits, then it'll keep the row.
Example:
Cell A289 Contains: 04245468 ← Keep this row
Cell A978 Contains: 04513 ← Delete this row
So far I have the following by using the left function within my code:
Sub CleanUpSheet1()
Dim RowA As Range
'hides any popups
Application.DisplayAlerts = False
'Deletes all blanks up to row 15,0000
Range("a2:A15000").Select
Selection.SpecialCells(xlCellTypeBlanks).EntireRow.Delete
For Each RowA In Range("A2:A" & ActiveSheet.UsedRange.Rows.Count)
If Left(RowA.Value, 5) <> "issue" And Right(RowA.Value, 4) <> "-000" And RowA.Value <> 0 Then
RowA.EntireRow.Delete
End If
Next
're-enables popups
Application.DisplayAlerts = True
End Sub
If it's just a matter of numbers you can transform the cell value into a string (RowA.Text or maybe Cstr(RowA.Value) and then test on the lenght :
if len(cstr(RowA.Value)) = 8 ???
(or len(RowA.Text))
Tell me if I havn't understood your question.
Had to reformat this a lot.
Sub CleanUpSelect1()
Dim RowA As Range
Dim cRng As Range
Dim iCounter As Long
Set RowA = Sheet1.Range("A2:A" & Sheets("Sheet1").UsedRange.Rows.Count)
iCounter = 1
Do
Set cRng = RowA(iCounter, 1) 'Loop rows
If CStr(cRng.Value2) = vbNullString Then
cRng.EntireRow.Delete
Else
If Not KeepRow(cRng.Value2) Then
cRng.EntireRow.Delete 'Delete row
Else
iCounter = iCounter + 1 'Advance
End If
End If
Loop While iCounter <= RowA.Rows.Count 'Stop after loop all rows
End Sub
Private Function KeepRow(RowValue As String) As Boolean
KeepRow = (RowValue Like "########" Or RowValue Like "issue#" Or RowValue Like "######-###")
End Function
But it works.
I've built this code, and it's working fine. However I expect there must be a more elegant way to embed the range 'c' into the Evaluate function rather than how I've used 'r' to determine the row number, and build that into the reference.
(I'm learning). Copy of (very stripped down) xlsm available here: https://www.dropbox.com/s/e6pcugqs4zizfgn/2018-11-28%20-%20Hide%20table%20rows.xlsm?dl=0
Sub HideTableRows()
Application.ScreenUpdating = False
Dim c As Range
Dim r As Integer
For Each c In Range("ForecastTable[[Group]:[Item]]").Rows
r = c.Row
If Application.Evaluate("=COUNTA(B" & r & ":D" & r & ") = 0") = True Then
c.EntireRow.Hidden = True
Else: c.EntireRow.Hidden = False
End If
Next c
Application.ScreenUpdating = True
End Sub
There's no specific question/problem, but here's my suggested code improvements.
Most notably, I wouldn't execute the Hidden procedure until you have all the rows. That way you don't have repeatedly do something that only need be completed once. This will always be the best practice when looping and manipulating data. Make changes to the sheet AFTER you have identified the range.
With the above change, you don't need to turn off ScreenUpdating.
The Evaluate function is fine, but isEmpty is probably the best option. There are probably slightly faster methods, perhaps checking multiple if-statements, but that's getting into fractions of a second over thousands of rows (probably not worth researching).
Technically you don't really need to loop by rows. You can get by with a single cell in a row, then checking the next two over, see utilization of Offset to generate that range. This also creates a more dynamic than using hard-coded columns ("A"/"B"...etc")
Long is recommended over Integer but this is pretty small, and I'm only mentioning it because I posted about it here.. Technically you don't even need it with the above changes.
Here's the code:
Sub HideTableRows()
Dim c As Range, hIdeRNG As Range, WS As Worksheet
'based on OP xlsm file.
Set WS = Sheet4
'used range outside of used range to avoid an if-statement on every row
Set hIdeRNG = WS.Cells(Rows.Count, 1)
'loops through range of single cells for faster speed
For Each c In Range("ForecastTable[Group]").Cells
If IsEmpty(Range(c, c.Offset(0, 2))) = 0 Then
'only need a single member in the row.
Set hIdeRNG = Union(hIdeRNG, c)
End If
Next c
'Hides rows only if found more than 1 cell in loop
If hIdeRNG.Cells.Count > 1 Then
Intersect(WS.UsedRange, hIdeRNG).EntireRow.Hidden = True
End If
End Sub
Final Thought: There's some major enhancements coming out to Excel supposedly in early 2019 that might be useful for this type of situation if you were looking for a non-VBA solution. Click here for more info from MS.
Flipping the logic a bit, why not just filter those three columns for blanks, then hide all the visible filtered blank rows in one go?
Something like this:
Sub DoTheHide()
Dim myTable As ListObject
Set myTable = Sheet4.ListObjects("ForecastTable")
With myTable.Range
.AutoFilter Field:=1, Criteria1:="="
.AutoFilter Field:=2, Criteria1:="="
.AutoFilter Field:=3, Criteria1:="="
End With
Dim rowsToHide As Range
On Error Resume Next
Set rowsToHide = myTable.DataBodyRange.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
myTable.AutoFilter.ShowAllData
If Not rowsToHide Is Nothing Then
rowsToHide.EntireRow.Hidden = True
End If
End Sub
Since c is used to iterate over the rows and each row contains the 3 cells in question ("=COUNTA(B" & r & ":D" & r & ") = 0") is equivalent to ("=COUNTA(" & c.Address & ") = 0"). But using the WorksheetFunction directly is a better appraoch.
It should be noted that Range("[Table]") will return the proper result as long as the table is in the ActiveWorkbook. It would be better to useThisWorkbook.Worksheets("Sheet1").Range("[Table]")`.
Sub HideTableRows()
Application.ScreenUpdating = False
Dim row As Range, target As Range
With Range("ForecastTable[[Group]:[Item]]")
.EntireRow.Hidden = False
For Each row In .rows
If Application.WorksheetFunction.CountA(row) = 0 Then
If target Is Nothing Then
Set target = row
Else
Set target = Union(target, row)
End If
End If
Next
End With
If Not target Is Nothing Then target.EntireRow.Hidden = True
Application.ScreenUpdating = True
End Sub
Proper syntax Match and If not isblank
I need some assistance with creating a loop statement that will determine the range start and end where a particular criteria is met.
I found these statements on the web and need help to modify them to loop thru two different worksheets to update a value on 1 of the worksheets.
This one has an issue returning True or False value for the Range when I want to pass the actual named range for look up where this field = Y, then returns the value from another column. I original tried using Match and If is not blank function. But that is very limiting.
See the previous post to see what I am trying to accomplish - I know I will need to expand the code samples and probably will need help with this modification.
Sub Test3()
Dim x As Integer
Dim nName As String
Sheets("BalanceSheet").Select
nName = Range("qryDifference[[Validate Adjustment]]").Select
Debug.PrintnName
' Set numrows = number of rows of data.
NumRows = Range(nName, Range(nName).End(xlDown)).Rows.Count
' Select cell a1.
' Establish "For" loop to loop "numrows" number of times.
For x = 1 To NumRows
' Insert your code here.
MsgBox"Value found in cell " & ActiveCell.Address
' Selects cell down 1 row from active cell.
ActiveCell.Offset(1, 0).Select
Next
End Sub
This is what I have so far - this is giving me and issue with
ActiveCell.Offset(4, 0).Select
nAgentNo = Range("qryDifference[[agtno]]").Value
nValidate = Range("ryDifference[[Difference]]").Value
Debug.Print nAgentNo
Debug.Print nValidate
Type mismatch error on the above.
Sub Revised_AgentAmount()
Dim myRange As Range
Dim i As Long, j As Long
Dim nAgentNo As String
Dim nValidate As Long
Sheets("BalanceSheet").Select
Set myRange = Range("qryDifference[[Validate Adjustment]]")
For i = 1 To myRange.Rows.Count
For j = 1 To myRange.Columns.Count
If myRange(i, j).Value = "Y" Then
ActiveCell.Offset(4, 0).Select
nAgentNo = Range("qryDifference[[agtno]]").Value
nValidate = Range("ryDifference[[Difference]]").Value
Debug.Print nAgentNo
Debug.Print nValidate
End If
Next j
Next i
End Sub
In your first statement you declare nName as a String then try to select it. You would need to declare it as a Range if you are going to use it as a Range object.
I found solution elsewhere with a if statement instead of the for loop.
=IF([#agtno]=B24,[#[agt_amt]],SUMPRODUCT((Balance!$B$2:$B$7=[#agtno])*(Balance!$F$2:$F$7="Y")*Balance!$E$2:$E$7)+[#[agt_amt]])
I currently have a macro that I use to delete a record if the ID doesn't exist in a list of ID's I created from an XML document. It does work like I want it to, however I have over 1000 columns in the spreadsheet (one for each day of the year until end of 2015) so it takes ages to delete the row and it can only do 1 or 2 before it says "Excel ran out of resources and had to stop". Below is the code I'm using for the macro, is there another way I can do this so that Excel doesn't run of of resources?
Sub deleteTasks()
Application.ScreenUpdating = False
Dim search As String
Dim sheet As Worksheet
Dim cell As Range, col As Range
Set sheet = Worksheets("misc")
Set col = sheet.Columns(4)
ActiveWorkbook.Sheets("Schedule").Activate
ActiveSheet.Range("A4").Select
ActiveSheet.Unprotect
ActiveSheet.Range("A:C").EntireColumn.Hidden = False
Do While ActiveCell.Value <> ""
search = ActiveCell.Value
Set cell = col.Find(What:=search, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If cell Is Nothing Then 'If the taskID is not in the XML list
Debug.Print "Deleted Task: " & ActiveCell.Value
Selection.EntireRow.Delete
End If
ActiveCell.Offset(1, 0).Select 'Select next task ID
Loop
ActiveSheet.Range("A:B").EntireColumn.Hidden = True
ActiveSheet.Protect
End Sub
After trying lots of different options, including all the answers listed below. I have realized that whatever the method is, deleting a row with ~1100 columns is going to take a while on my average laptop (2.20 Ghz, 4GB RAM). Since the majority of the rows are empty I have found alternative method which is a lot faster. I just clear the cells which contain data (A:S) and then resize the table to remove the row where I just deleted the data from. This end result is exactly the same as entireColumn.Delete. Below is the code I'm using now
'New method - takes about 10 seconds on my laptop
Set ws = Worksheets("Schedule")
Set table = ws.ListObjects(1)
Set r = ws.Range("A280:S280")
r.Clear
table.Resize Range("A3:VZ279")
Using anything involving EntireColumn.Delete or just manually selecting the row and deleting it takes about 20-30 seconds on my laptop. Of course this method only works if your data is in a table.
The short answer:
Use something like
ActiveSheet.Range(DelStr).Delete
' where DelStr = "15:15" if you want to delete row 15
' = "15:15,20:20,32:32" if you want to delete rows 15,20 and 32
The long answer:
Important: If you have ~ 30 / 35 rows to delete, the following code works very efficiently. Beyond which it would throw up an error. For code to handle arbitrary number of rows efficiently see the very long answer below this.
If you have a function which lets you list out which rows you want to delete, try the code below. This is what I use to very efficiently delete multiple rows with minimum overhead. (the example assumes that you've obtained the rows you need to delete through some program, here I manually feed them in):
Sub DeleteRows()
Dim DelRows() As Variant
ReDim DelRows(1 To 3)
DelRows(1) = 15
DelRows(2) = 18
DelRows(3) = 21
'--- How to delete them all together?
Dim i As Long
For i = LBound(DelRows) To UBound(DelRows)
DelRows(i) = DelRows(i) & ":" & DelRows(i)
Next i
Dim DelStr As String
DelStr = Join(DelRows, ",")
' DelStr = "15:15,18:18,21:21"
'
' IMPORTANT: Range strings have a 255 character limit
' See the other code to handle very long strings
ActiveSheet.Range(DelStr).Delete
End Sub
The (very long) efficient solution for arbitrary number of rows and benchmark results:
Here are the benchmark results obtained by deleting rows (Time in seconds vs. no. of rows).
The rows are on a clean sheet and contain a volatile formula in the D column from D1:D100000
i.e. for 100,000 rows, they have a formula =SIN(RAND())
The code is long and not too pretty, but it splits the DelStr into 250 character substrings and forms a range using these. Then the new DeleteRng range is deleted in a single operation.
The time to delete may depend on the contents of the cells. The testing/benchmarking, in congruence with a bit of intuition suggests the following results.
Sparse rows/empty cells delete fastest
Cells with values take somewhat longer
Cells with formulas take even longer
Cells which feed into formulas in other cells take longest as their deletion triggers the #Ref reference error.
Code:
Sub DeleteRows()
' Usual optimization
' Events not disabled as sometimes you'll need to interrupt
' You can optionally keep them disabled
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
' Declarations...
Dim DelRows() As Variant
Dim DelStr As String, LenStr As Long
Dim CutHere_Str As String
Dim i As Long
Dim MaxRowsTest As Long
MaxRowsTest = 1000
' Here I'm taking all even rows from 1 to MaxRowsTest
' as rows to be deleted
ReDim DelRows(1 To MaxRowsTest)
For i = 1 To MaxRowsTest
DelRows(i) = i * 2
Next i
'--- How to delete them all together?
LenStr = 0
DelStr = ""
For i = LBound(DelRows) To UBound(DelRows)
LenStr = LenStr + Len(DelRows(i)) * 2 + 2
' One for a comma, one for the colon and the rest for the row number
' The goal is to create a string like
' DelStr = "15:15,18:18,21:21"
If LenStr > 200 Then
LenStr = 0
CutHere_Str = "!" ' Demarcator for long strings
Else
CutHere_Str = ""
End If
DelRows(i) = DelRows(i) & ":" & DelRows(i) & CutHere_Str
Next i
DelStr = Join(DelRows, ",")
Dim DelStr_Cut() As String
DelStr_Cut = Split(DelStr, "!,")
' Each DelStr_Cut(#) string has a usable string
Dim DeleteRng As Range
Set DeleteRng = ActiveSheet.Range(DelStr_Cut(0))
For i = LBound(DelStr_Cut) + 1 To UBound(DelStr_Cut)
Set DeleteRng = Union(DeleteRng, ActiveSheet.Range(DelStr_Cut(i)))
Next i
DeleteRng.Delete
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
The code to generate the formulas in a blank sheet is
Sub FillRandom()
ActiveSheet.Range("D1").FormulaR1C1 = "=SIN(RAND())"
Range("D1").AutoFill Destination:=Range("D1:D100000"), Type:=xlFillDefault
End Sub
And the code to generate the benchmark results above is
Sub TestTimeForDeletion()
Call FillRandom
Dim Time1 As Single, Time2 As Single
Time1 = Timer
Call DeleteRows
Time2 = Timer
MsgBox (Time2 - Time1)
End Sub
Note: Many thanks to brettdj for pointing out the error which gets thrown when the length of DelStr exceeding 255 characters. It seems to be a known problem and as I painfully found out, it still exists for Excel 2013.
This code uses AutoFilter and is significantly faster than looping through rows.I use it daily and it should be pretty easy to figure out.Just pass it what you're looking for and the column to search in.You could also hard-code the column if you want.
private sub PurgeRandy
Call FindDelete("F", "Randy")
end sub
Public Sub FindDelete(sCOL As String, vSearch As Variant) 'Simple find and Delete
Dim lLastRow As Integer
Dim rng As Range
Dim rngDelete As Range
Range(sCOL & 1).Select
[2:2].Insert
[2:2] = "***"
Range(sCOL & ":" & sCOL).Select
With ActiveSheet
.UsedRange
lLastRow = .Cells.SpecialCells(xlCellTypeLastCell).Row
Set rng = Range(sCOL & 2, Cells(lLastRow, sCOL))
rng.AutoFilter Field:=1, Criteria1:=vSearch
Set rngDelete = rng.SpecialCells(xlCellTypeVisible)
rng.AutoFilter
rngDelete.EntireRow.Delete
.UsedRange
End With
End Sub
In this case a simple working formula can be used to see if each of the values in your range to be tested (column A of schedule) exist in column F of misc
In B4 it would =MATCH(A4,misc!D:D,0)
This can be used manually or with code for an efficient delete as the formula by design returns an error if there is no match which we can efficiently delete with VBA with either:
AutoFilter
SpecialCells (the design piece*)
In xl2007 note that there is a limit of 8192 discrete areas that can be selected with SpecialCells
code
Sub ReCut()
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim rng1 As Range
Set ws1 = Sheets("misc")
Set ws2 = Sheets("schedule")
With Application
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
End With
Set rng1 = ws2.Range(ws2.[a4], ws2.Cells(Rows.Count, "A").End(xlUp))
ws2.Columns(2).Insert
With rng1.Offset(0, 1)
.FormulaR1C1 = "=MATCH(RC[-1],'" & ws1.Name & "'!C[2],0)"
On Error Resume Next
.Cells.SpecialCells(xlCellTypeFormulas, xlErrors).EntireRow.Delete
On Error GoTo 0
End With
ws2.Columns(2).Delete
With Application
.ScreenUpdating = True
.EnableEvents = True
.DisplayAlerts = True
End With
End Sub
Note: I don't have enough "reputation" to add my comments thus posting as answer. Credit to hnk for wonderful answer (Long Answer). I have one edit as suggestion:
Once you split the long string and in case the last block is more than the set character then it is having "!" at the end which is throwing error for range method. Addition of IF statement and MID is ensuring that there is no such character.
To handle that, use:
For i = LBound(DelStr_Cut) + 1 To UBound(DelStr_Cut)
If Right(DelStr_Cut(i), 1) = "!" Then
DelStr_Cut(i) = Mid(DelStr_Cut(i), 1, Len(DelStr_Cut(i)) - 1)
Set DeleteRng = Union(DeleteRng, ActiveSheet.Range(DelStr_Cut(i)))
Else
Set DeleteRng = Union(DeleteRng, ActiveSheet.Range(DelStr_Cut(i)))
End If
Next i
Thanks,
Bakul
In line with a previous question I asked I am trying to hide rows that contain zeros, but skip over rows that contain any text in any one or more cells. I received excellent help previously skipping blank rows, and was hoping for more help now. I've searched through the internet on every forum I can find and have found nothing that does what I need it to. There are two codes on that hides and an exact copy of that one but with hide set to false. Here is the one that Hides.
Sub HideRows()
Dim R As Long
Dim Rng As Range
If Selection.Rows.Count > 1 Then
Set Rng = Selection
Else
Set Rng = ActiveSheet.UsedRange
End If
For R = 1 To Rng.Rows.Count
Set myRange = Range(Rng(R, 2), Rng(R, Rng.Columns.Count))
If Application.CountBlank(myRange) <> myRange.Cells.Count And IsNumeric(myRange(Row)) = False Then
If Application.Sum(myRange) = 0 Then
Rng.Rows(R).Hidden = True
End If
End If
Next R
End Sub
By the way I know that the IsNumeric(myRange(Row)) = False really should probably be = True, but for some reason on one of my worksheets this setup works and if I change to True it pretty much does nothing.
Thanks in Advance for any help.
When I tried your code, I got the following syntax errors:
myRange is not defined.
Row (as in myRange(Row)) is undefined.
Other issues with your code:
myRange is a range so IsNumeric(myRange) will always be false.
If Application.CountBlank(myRange) <> myRange.Cells.Count means blank rows are not hidden.
IsNumeric and IsNumber both operate on a single value. I can find nothing in the documentation to suggest they can be made to operate on arrays, collections or ranges. My experiments have produced results consistant with this. I do not believe there is any way of handling the difficult cases except by checking individual cells within a row.
I think I have tested the following code for all the boundary conditions but I cannot guarantee this. It hides blank rows and rows that contain nothing but zeros. If a range is selected, columns outside that range are treated as blank.
Sub HideRows()
Dim ColCrnt As Integer
Dim Hide As Boolean
Dim myRange As Range
Dim R As Long
Dim Rng As Range
If Selection.Rows.Count > 1 Then
Set Rng = Selection
Else
Set Rng = ActiveSheet.UsedRange
End If
For R = 1 To Rng.Rows.Count
Set myRange = Range(Rng(R, 1), Rng(R, Rng.Columns.Count))
If Application.CountBlank(myRange) = myRange.Cells.Count Then
' Blank row
Hide = True
ElseIf Application.Sum(myRange) <> 0 Then
' At least on numeric cell with a non-zero value
Hide = False
Else
' Row contains one or more cells containing text, booleans or zeroes
' Hide if all these cells are zeros.
ColCrnt = Rng.Columns.Count
Set myRange = Rng(R, ColCrnt)
If IsCellZero(myRange) Or IsEmpty(myRange) Then
' Last cell of row is zero or blank so will have to check row
Do While True
' Skip to first non-blank cell to left or column 1
' if no non-blank cells
Set myRange = myRange.End(xlToLeft)
If myRange.Column < Rng(R, 1).Column Then
' Have move outside selection
Hide = True
Exit Do
End If
If myRange.Column = Rng(R, 1).Column Then
' Have reached column 1
If IsCellZero(myRange) Or IsEmpty(myRange) Then
' Column 1 is zero or blank so nothing interesting on row
Hide = True
Exit Do
Else
' Column 1 is not zero or blank
Hide = False
Exit Do
End If
End If
If Not IsCellZero(myRange) Then
Hide = False
Exit Do
End If
If myRange.Column = Rng(R, 1).Column Then
' No non-zero cells found
Hide = True
Exit Do
End If
Loop
Else
' Last cell of row is neither zero nor empty
Hide = False
End If
End If
If Hide Then
Rng.Rows(R).Hidden = True
Else
Rng.Rows(R).Hidden = False
End If
Next R
End Sub
Function IsCellZero(Rng As Range) As Boolean
' Rng must be a single cell. Returns true only if Rng.Value is numeric zero
' Function uses IsNumber because IsNumeric returns True
' for empty cells and booleans
If Application.WorksheetFunction.IsNumber(Rng.Value) Then
If Val(Rng.Value) = 0 Then
IsCellZero = True
Else
IsCellZero = False
End If
Else
' Value is blank, text or boolean
IsCellZero = False
End If
End Function
The cause of your problems is And IsNumeric(myRange(Row)) = False
Row is undefined and never set. So it will have the default value of 0. Therefore (since myRange is defined starting at column 2) myRange(Row) refers to the single cell in column A on the row myRange refers to.
If you drop the (Row) bit, IsNumeric will always return FALSE
Also, Set myRange = Range(Rng(R, 2), refers to Row R of the used range, offset one column to the right
Conclusion:
Assuming you want to test all cells, change to `Set myRange = Range(Rng(R, 1), Rng(R, Rng.Columns.Count))
To correctly test for no non-numeric cells use
If Application.Count(myRange) > 0 And _
Application.CountBlank(myRange) + _
Application.Count(myRange) = myRange.Cells.Count Then
By the way, its good practice DIM all you variables. This would have identified the issue with (Row). If you add Option Explicit to the top of your module this will become manditory.