Looping through sheets to delete certain cells - excel

I wish to delete specific cells from the sheets in a workbook. While doing so it should also delete specific cells having formula error in these worksheets of the workbook.
I used a recent program in stackoverflow by #Blind Seer as per following link which is for similar applications.
incorporating-sheet-loop
Sample of workbook sheets before program run are appended below
Code adopted by me as follows.
Sub DeleteCells()
Dim rng As Range, rngError As Range, delRange As Range
Dim i As Long, j As Long, k As Long
Dim wks As Worksheet
On Error Resume Next
Set rng = Application.InputBox("Select cells To be deleted", Type:=8)
On Error GoTo 0
If rng Is Nothing Then Exit Sub Else rng.Delete
For k = 1 To ThisWorkbook.Worksheets.Count 'runs through all worksheets
Set wks = ThisWorkbook.Worksheets(k)
With wks
For i = 1 To 7 '<~~ Loop trough columns A to G
'~~> Check if that column has any errors
On Error Resume Next
Set rngError = .Columns(i).SpecialCells(xlCellTypeFormulas, xlErrors)
On Error GoTo 0
If Not rngError Is Nothing Then
For j = 1 To 100 '<~~ Loop Through rows 1 to 100
If .Cells(j, i).Text = "#DIV/0!" Then
'~~> Store The range to be deleted
If delRange Is Nothing Then
Set delRange = .Columns(i)
Exit For
Else
Set delRange = Union(delRange, .Columns(i))
End If
End If
Next j
End If
Next i
End With
Next k
'~~> Delete the range in one go
If Not delRange Is Nothing Then delRange.Delete
End Sub
After running the code it deletes the cell input in the input box ie it blanks out the data in the cell and append rest of the data in the row at the end of the last filled row. It is not blanking out error cells and the program gives the error message:
Method 'Union of object_Global failed
on the following code line
'Set delRange = Union(delRange, .Columns(i))'
Sample data after proram run is appended below.
Please help in locating the error in the program. Result desired is Input cell range should blank out retaining its row position. Same also for error cells.
Thanks

Option Explicit
Sub DeleteCells()
Dim ws As Worksheet, rng As Range, rngErr As Range
On Error Resume Next
Set rng = Application.InputBox("Select cells to be deleted", Type:=8)
If Not rng Is Nothing Then
rng.Delete
For Each ws In ThisWorkbook.Worksheets
Set rngErr = ws.UsedRange.SpecialCells(xlCellTypeFormulas, xlErrors)
If Not rngErr Is Nothing Then rngErr.Clear
Next
End If
End Sub

Not much of a solution but the reason for the error is that Union does not work across worksheets. It will work for ranges on a single sheet.
You could adapt your code to work one sheet at a time:
Sub DeleteCells()
Dim rng As Range, rngError As Range, delRange As Range
Dim i As Long, j As Long, k As Long
Dim wks As Worksheet
On Error Resume Next
Set rng = Application.InputBox("Select cells To be deleted", Type:=8)
On Error GoTo 0
If rng Is Nothing Then Exit Sub Else rng.Delete
For k = 1 To ThisWorkbook.Worksheets.Count 'runs through all worksheets
'Set wks = ThisWorkbook.Worksheets(k)
'With wks
With ThisWorkbook.Worksheets(k) '<<do each sheet individually so that Union functions as expected
For i = 1 To 7 '<~~ Loop trough columns A to G
'~~> Check if that column has any errors
On Error Resume Next
Set rngError = .Columns(i).SpecialCells(xlCellTypeFormulas, xlErrors)
On Error GoTo 0
If Not rngError Is Nothing Then
For j = 1 To 100 '<~~ Loop Through rows 1 to 100
If .Cells(j, i).Text = "#DIV/0!" Then
'~~> Store The range to be deleted
If delRange Is Nothing Then
Set delRange = .Columns(i)
Exit For
Else
Set delRange = Union(delRange, .Columns(i))
End If
End If
Next j
End If
Next i
End With
Next k
'~~> Delete the range in one go
If Not delRange Is Nothing Then delRange.Delete
End Sub

You can use IsNumeric to check if the cells contain numeric values. Errors are not numeric values, so IsNumeric(Cell with error) = False. I modified your code:
Set wks = ThisWorkbook.Worksheets(k)
With wks
For i = 1 To 7 '<~~ Loop trough columns A to G
'~~> Check if that column has any errors
On Error Resume Next
Set rngError = .Columns(i).SpecialCells(xlCellTypeFormulas, xlErrors)
On Error GoTo 0
If Not rngError Is Nothing Then
For j = 1 To 100 '<~~ Loop Through rows 1 to 100
If Not IsNumeric(.Cells(j, i)) Then
'~~> Store The range to be deleted
If delRange Is Nothing Then
Set delRange = .Columns(i)
Exit For
Else
Set delRange = Union(delRange, .Columns(i))
End If
End If
Next j
End If
Next i
End With
Next k
'~~> Delete the range in one go
If Not delRange Is Nothing Then delRange.Delete
End Sub
Note: This means that if sometimes text is to be entered, it will count it as an ERROR. So be careful if that's the case!
Also, as per my comment; If your cells are quotients of cells on other cells, consider using this instead of code; support.microsoft.com/en-us/kb/182188. To simply skip the divisions.

Related

How to delete a row if there is no value in a column?

I'm trying to delete rows in table if there is no value in a certain column.
I've used a code that deletes rows if there is one cell value missing, but I would like to delete rows if a cell does not contain a value in a certain column.
For example, if there is no value in Column G Row 5 then I want to delete the entire row.
Sub Test2()
Dim rng As Range
On Error Resume Next
Set rng = Range("Table3").SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If Not rng Is Nothing Then
rng.Delete Shift:=xlUp
End If
End Sub
This deletes all rows with any type of missing cell value.
Two small changes:
Sub Test2()
Dim rng As Range
On Error Resume Next
Set rng = Range("G:G").SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If Not rng Is Nothing Then
rng.EntireRow.Delete Shift:=xlShiftUp
End If
End Sub
EDIT:
If you want to work directly with the table, then consider iterating over the ListRows of the table in question, something like this:
Sub Test2()
Dim myTbl As ListObject
Set myTbl = Sheet1.ListObjects("table3") ' change sheet as necessary
Dim indx As Long
indx = myTbl.ListColumns("ColumnName").Index
Dim rngToDelete As Range
Dim myRw As ListRow
For Each myRw In myTbl.ListRows
If IsEmpty(myRw.Range(1, indx).Value) Then
If rngToDelete Is Nothing Then
Set rngToDelete = myRw.Range
Else
Set rngToDelete = Union(rngToDelete, myRw.Range)
End If
End If
Next myRw
If Not rngToDelete Is Nothing Then
rngToDelete.Delete Shift:=xlShiftUp
End If
End Sub
Note: Technically, it's xlShiftUp, not xlUp.

How can I have my loop search for a value rather than a string of words?

I have some data that has both words and values in cells and I am trying to delete the rows that don’t have values in the cells. My code works now if all of the numbers are negative but if there are positive numbers then my code won’t work. How do I fix this?
Sub tval
Dim s As Long
Dim LastRow As Long
S=2
LastRow= cells.find(“*”,[A1],,, xlByRows,xlPreviousRow).row
Do until s>LastRow
DoEvents
If InStr(1,Cells(s,4), “-“) > 0 Then
S=s+1
Else
Cells(s,4).EntireRow.Delete
LastRow=LastRow -1
End if
Loop
End sub
When deleting rows, you should always start from the end.
Sub tval
Dim s As Long
Dim LastRow As Long
LastRow= Cells(Rows.Count, 1).End(xlUp).Row
For s= LastRow to 2 Step -1
If Not IsNumeric(Cells(s,4)) then
Cells(s,4).EntireRow.Delete
End if
Next s
End sub
This should work for you:
Sub tgr()
Dim ws As Worksheet
Dim rTextConstants As Range
Dim rTextFormulas As Range
Dim rCombined As Range
Set ws = ActiveWorkbook.ActiveSheet
'Exclude row 1 so that only text values found in rows 2+ are found
With ws.Range("A2", ws.Cells(ws.Rows.Count, ws.Columns.Count))
On Error Resume Next 'prevent error if no cells found
Set rTextConstants = .SpecialCells(xlCellTypeConstants, xlTextValues)
Set rTextFormulas = .SpecialCells(xlCellTypeFormulas, xlTextValues)
On Error GoTo 0 'remove on error resume next condition
End With
If Not rTextConstants Is Nothing Then Set rCombined = rTextConstants
If Not rTextFormulas Is Nothing Then
If rCombined Is Nothing Then Set rCombined = rTextFormulas Else Set rCombined = Union(rCombined, rTextFormulas)
End If
If Not rCombined Is Nothing Then
rCombined.EntireRow.Delete
Else
MsgBox "No cells containing text found in sheet '" & ws.Name & "'", , "Error"
End If
End Sub
May I suggest a bit of a different approach:
Before:
Code:
Dim RNG1 As Range, RNG2 As Range
Option Explicit
Sub TestCase()
With ActiveWorkbook.Sheets(1)
Set RNG1 = .Range("A1:A" & .Cells(Rows.Count, 1).End(xlUp).Row)
If RNG1.SpecialCells(xlCellTypeConstants, 1).Count <> RNG1.Cells.Count Then
Set RNG2 = Application.Intersect(RNG1, RNG1.SpecialCells(xlCellTypeConstants, 2))
RNG2.EntireRow.Delete
End If
End With
End Sub
After:
You'll need to change this around to suit your range obviously. It should be a good starting point nonetheless.
You can also use AutoFilter to filter the numbers, and delete the visible cells to accomplish this task. The code accounts for a header row.
With ThisWorkbook.Sheets("Sheet1")
With .Range("A1").CurrentRegion
.AutoFilter
.AutoFilter Field:=4, Criteria1:="<>*"
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
.AutoFilter
End With
End With

Delete rows with merged cells

I found a procedure to highlight merged cells in an active sheet:
I tried a ActiveCell.EntireRow.Delete statement to delete the row that is currently iterated over.
Sub DeleteRows()
Dim x As Range
For Each x In ActiveSheet.UsedRange
If x.MergeCells Then
x.Interior.ColorIndex = 8
ActiveCell.EntireRow.Delete
End If
Next
End Sub
I don't care about highlighting the merged cells. The goal is to delete any row that has a merged cell.
Find out all merged cell ranges, club them and delete in one go.
Sub DeleteRows()
Dim x As Range
Dim rngDelete As Range
For Each x In ActiveSheet.UsedRange
If x.MergeCells Then
If rngDelete Is Nothing Then
Set rngDelete = x
Else
Set rngDelete = Union(rngDelete, x)
End If
End If
Next
If Not rngDelete Is Nothing Then
rngDelete.EntireRow.Delete
End If
End Sub
When deleting rows, always delete from the bottom up or a) you risk deleting the next cell you want to examine and b) you risk skipping over a row that comes up to take the place of a deleted row.
Sub DeleteRows()
Dim r as long, c as long
with ActiveSheet.UsedRange
'work backwards through the rows
For r = .rows.count to 1 step -1
'work forwards through the columns
For c = 1 to .columns.count
If .cells(r, c).MergeCells Then
'once a merged cell is found, delete then go immediately to the next row
.cells(r, c).EntireRow.Delete
exit for
End If
next c
Next r
end with
End Sub
A quick way to do this is to find all the merged cells then delete them in one go: a good way to do this is to use a range.find using a cells 'format' as merged then combine the found ranges
The following code loops through merged ranges and creates a union then selects the entire rows
Sub SelectMerge()
Dim rng As Range, rngUnion As Range, Test As Range
Dim ws As Worksheet: Set ws = ActiveSheet
With Application.FindFormat
.Clear
.MergeCells = True
End With
With ws.UsedRange
Set rng = .Find("", SearchFormat:=True)
Do
If Not rngUnion Is Nothing Then Set rngUnion = Application.Union(rng, rngUnion)
If rngUnion Is Nothing Then Set rngUnion = rng
If rng Is Nothing Then Exit Do
Set rng = .Find("", After:=rng, SearchFormat:=True)
Loop While Application.Intersect(rng, rngUnion) Is Nothing
End With
If Not rngUnion Is Nothing Then rngUnion.EntireRow.Select 'rngUnion.EntireRow.Delete
End Sub

VBA macro delete cells containing #N/A and shift up the cells (not the rows)

I'm creating a ranking and I need to delete all the cells with #N/A (pasted as text, not formula) and to delete those cells and shhift them up.
The worksheet contains 503 raws and I need it from column A to T.
Thanks in advance, I have tried so many VBA codes of this web and I'm not able to find something that works.
Try,
dim rng as range
with worksheets("sheet1")
on error resume next
set rng = .range("A:T").specialcells(xlcelltypeformulas, xlerrors)
if not rng is nothing then
rng.delete shift:=xlup
end if
set rng = .range("A:T").specialcells(xlcelltypeconstants, xlerrors)
if not rng is nothing then
rng.delete shift:=xlup
end if
on error goto 0
end with
This should work. There are faster ways of doing what you ask, but since you don't have that big of a data set, I just modified some code I had available.
Sub KillPoundNa()
Dim rCell As Range, WS As Worksheet, KillRng As Range, UndesireableText As String
UndesireableText = "#N/A"
Set WS = ActiveSheet
Set KillRng = WS.Cells(Rows.Count, 1)
For Each rCell In WS.UsedRange.Cells
If InStr(1, rCell.Text, UndesireableText, vbTextCompare) > 0 Then
Set KillRng = Union(KillRng, rCell)
End If
Next rCell
KillRng.Delete (xlUp)
End Sub

In range find this and do that

Have a range of cell with column headings as weeks In the range of cells I want to look for a number, say
1 if it finds a 1 then look at a column in said row for a variable, 2 or 4 whatever Now I want to put a triangle (can be copy and paste a cell) in the cell that has the "1" in it then skip over the number of week variable and add another triangle and keep doing this until the end of the range. Then skip down to the next row and do the same, until the end of the range.
Then change to the next page and do the same thing... through the whole workbook.
I think I have it done, don't know if it's the best way.
I get a error 91 at the end of the second loop, the first time the second loop ends it goes through the error code.
The second time the second loop ends it errors.
I don't understand it runs through once, but not twice.
Sub Add_Triangles2()
Dim Rng As Range
Dim OffNumber As Integer
Dim SetRange As Range
Dim OffsetRange As Range
Dim ws As Worksheet
Set SetRange = Sheets("Sheet1").Range("G25") ' Used to stop the second loop in range
Worksheets(1).Activate
Worksheets(1).Range("A1").Select ' Has item to be pasted (a triangle)
Selection.Copy
For Each ws In Worksheets
Worksheets(ws.Name).Activate
With Range("C4:G25")
Set Rng = .Find(1, LookIn:=xlValues)
If Not Rng Is Nothing Then
FirstAddress = Rng.Address
Do
Rng.Activate
ActiveSheet.Paste
Do
OffNumber = Range("A" & ActiveCell.Row)
Set OffsetRange = SetRange.Offset(0, -OffNumber)
If Not ActiveCell.Address < OffsetRange.Address Then
Exit Do
Else
End If
ActiveCell.Offset(, OffNumber).Select
ActiveSheet.Paste
Loop While (ActiveCell.Address <= OffsetRange.Address)
On Error GoTo ErrorLine
Set Rng = .FindNext(Rng)
Loop While Not Rng Is Nothing And Rng.Address <> FirstAddress
End If
End With
ErrorLine:
On Error GoTo 0
Application.EnableEvents = True
Next ws
Application.CutCopyMode = False
End Sub
I was not able to get an Error 91 using the data set I built from your explanation, maybe a screenshot of the layout could help recreate the issue.
However, I would do something like this, it will look at the value of each cell in the range C4:G25, and if it equals 1, it will paste the symbol stored in Cell A1.
Sub Add_Triangles2()
Dim Rng As Range
Dim rngSymbol As Range
Dim intFindNum As Integer
Dim ws As Worksheet
Set rngSymbol = Range("A1") 'Set range variable to hold address of symbol to be pasted
intFindNum = 1 'Used to hold number to find
Worksheets(1).Activate
For Each ws In Worksheets
Worksheets(ws.Name).Activate
For Each Rng In Range("C4:G25")
If Rng.Value = intFindNum Then
rngSymbol.Copy Rng
End If
Next Rng
Next ws
End Sub
I got it....
Sub Add_TriWorking()
Dim Rng As Range
Dim rngSymbol As Range
Dim intFindNum As Integer
Dim ws As Worksheet
Dim OffNumber As Integer
Dim SetRange As Range
Dim OffsetRange As Range
Set SetRange = Sheets("Sheet1").Range("G25") ' Used to stop the second loop in range
Set rngSymbol = Range("A1") 'Set range variable to hold address of symbol to be pasted
intFindNum = 1 'Used to hold number to find
Worksheets(1).Activate
For Each ws In Worksheets
Worksheets(ws.Name).Activate
For Each Rng In Range("C4:G25")
If Rng.Value = intFindNum Then
rngSymbol.Copy Rng
Rng.Activate
ActiveCell.Copy
Do
OffNumber = Range("A" & ActiveCell.Row)
Set OffsetRange = SetRange.Offset(0, -OffNumber)
If Not ActiveCell.Address < OffsetRange.Address Then
Exit Do
Else
End If
ActiveCell.Offset(, OffNumber).Select
ActiveSheet.Paste
Loop While (ActiveCell.Address <= OffsetRange.Address)
On Error GoTo ErrorLine
End If
Next Rng
ErrorLine:
On Error GoTo 0
Application.EnableEvents = True
Next ws
Application.CutCopyMode = False
End Sub

Resources