How to apply IFERROR to all cells in Excel - excel

I have many cells that have #DIV/0! so I need to put the IFERROR function. Is there a way to apply this formula to all cells instead of putting the formula manually in every cell?
I tried this VBA code but I am looking for something more simple.
Sub WrapIfError()
Dim rng As Range
Dim cell As Range
Dim x As String
If Selection.Cells.Count = 1 Then
Set rng = Selection
If Not rng.HasFormula Then GoTo NoFormulas
Else
On Error GoTo NoFormulas
Set rng = Selection.SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
End If
For Each cell In rng.Cells
x = cell.Formula
cell = "=IFERROR(" & Right(x, Len(x) - 1) & "," & Chr(34) & Chr(34) & ")"
Next cell
Exit Sub
'Error Handler
NoFormulas:
MsgBox "There were no formulas found in your selection!"
End Sub
Can anyone help me?

Perhaps one of these versions will be easier to teach.
Sub apply_Error_Control()
Dim cel As Range
For Each cel In Selection
If cel.HasFormula Then
'option 1
cel.Formula = Replace(cel.Formula, "=", "=IFERROR(", 1, 1) & ", """")"
'option 2
'cel.Formula = "=IFERROR(" & Mid(cel.Formula, 2) & ", """")"
End If
Next cel
End Sub
I've supplied two ways to apply the IFERROR function as a 'wapper' for error control. To use the second option, comment the first and uncomment the second.
Select one or more cells and then run the macro; typically though Alt+F8 then Run from the worksheet.

Related

Apply IF to range of cells in excel VBA

I'm trying to have the following code applied to cells 19:500 in Column I. If I remove the set Range line of code, I19 updates properly but Once i add the range, the following code stops working? Does anyone know where I'm going wrong? Thanks!
Sub Status_Load()
Dim Cell As Range
Dim Range As Range
Dim Today As Date
With Sheet1
Set Range = .Range("I19:I500")
For Each Cell In Range
If Range("N19").Value = Empty Then Exit Sub
If Range("O19").Value <> Month(Today) Then
Range("I19").Value = "Carried"
ElseIf Range("S19").Value <> "" Then
Range("I19").Value = "Closed"
Else: Range("I19").Value = "Open"
End If
Next Cell
End With
End Sub
Use a regular For...Next loop and loop the rows:
Dim i as Long
For i = 19 to 500
If IsEmpty(.Range("N" & i).Value) Then Exit Sub
If .Range("O" & i).Value <> Month(Date) Then
.Range("I" & i).Value = "Carried"
ElseIf .Range("S" & i).Value <> "" Then
.Range("I" & i).Value = "Closed"
Else
.Range("I" & i).Value = "Open"
End If
Next
Side notes (as mentioned in comments):
Dim Range As Range: bad idea. Don't reuse members of the object model as variable names.
If you don't add the . in front of each Range call within the loop, then you're not actually referencing the With Sheet1.
Dim Today As Date. Perhaps you didn't include the line in your question Today = Date? In any case, you can just drop that variable and use Date directly, i.e. Month(Today) --> Month(Date).
EDIT:
As discussed in the comments, you may just be able to use a formula here and avoid VBA:
=IF(S66<>"","Closed",IF(AND(O66<>"",OR(MONTH(O66)<>MONTH(TODAY()),YEAR(O66)<>YEAR(TODAY()))),"Carried",IF(N66<>"","Open","")))

bold cell based on specific value in column J

I already tried using this code and its not working
Sub Bold()
With Sheets("1470")
For Each Cell In Range("J:J")
If Cell.Value = "N/A" Then
Cell.Font.bold = True
End If
Next Cell
End With
End Sub
the output that I want to execute is every cell in column J that contains "N/A" gets bold
I got error
"Type mismatch"
Do not use J:J It will slow your code. Find the last row and then check in that range.
To specifically check for #N/A use CVErr() as shown below.
If you want to check for any error then go with IsError() as mentoned by #PawelCzyz.
Is this what you are trying?
With Sheets("1470")
lrow = .Range("J" & .Rows.Count).End(xlUp).Row
For Each cell In Range("J1:J" & lrow)
If CVErr(cell.Value) = CVErr(xlErrNA) Then
cell.Font.Bold = True
End If
Next cell
End With
This answer is based on the assumption you looking for #N/A errors on your worksheet caused by the same formulas in that column.
Sub Test()
Dim rng1 As Range, rng2 As Range
With ThisWorkbook.Sheets("1470")
Set rng1 = .Range("J1:J" & .Range("J" & .Rows.Count).End(xlUp).Row)
If .Evaluate("=SUM(--ISNA(" & rng1.Address & "))") > 0 Then
Set rng2 = Intersect(rng1, rng1.SpecialCells(xlCellTypeFormulas, xlErrors))
rng2.Font.Bold = True
End If
End With
End Sub

vba - selection of cell references of empty cells in a row

Via the following code
Sub Macro1()
Worksheets("Sheet1").Rows("1:1").SpecialCells(xlCellTypeBlanks).Select
End Sub
I can select the empty cells in a row. Is there a way to retrieve all cell references of these cells? With cell references I mean x and y in
Cells(x,y)
This would do it: -
Public Sub Sample()
Dim Rng As Range
Dim Cl As Range
Worksheets("Sheet1").Rows("1:1").SpecialCells(xlCellTypeBlanks).Select
Set Rng = Selection
For Each Cl In Rng.Cells
Debug.Print "Row: " & Cl.Row & ", Column: " & Cl.Column
Next
Set Rng = Nothing
End Sub
Your line of code selected what you wanted, the code references that selection as Rng using Selection. It then loops through each item in Rng as Cl.
The Select and Selection in Gary's answer are not recommend. Consider using the below for a more concise and efficient method of achieving the same thing.
Public Sub Sample()
Dim Cl As Range
For Each cl In Worksheets("Sheet1").Rows("1:1").SpecialCells(xlCellTypeBlanks).Cells
Debug.Print "Row: " & Cl.Row & ", Column: " & Cl.Column
Next
End Sub

how to iterate over all rows of a excel sheet in VBA

I have this code (This code is in Access VBA which tries to read an excel file and after checking, possibly import it):
Set ExcelApp = CreateObject("Excel.application")
Set Workbook = ExcelApp.Workbooks.Open(FileName)
Set Worksheet = Workbook.Worksheets(1)
now I want to iterate over all rows of the excel worksheet. I want something such as this:
for each row in Worksheet.rows
ProcessARow(row)
next row
where
function ProcessARow(row as ???? )
' process a row
' how Should I define the function
' how can I access each cell in the row
' Is there any way that I can understand how many cell with data exist in the row
end function
My questions:
How to define the for each code that it iterate correctly on all
rows that has data?
How to define ProcessARow properly
How to get the value of each cell in the row.
How to find how many cell with data exist in the row?
Is there any way that I detect what is the data type of each cell?
edit 1
The link solves on problem :
How to define the for each code that it iterate correctly on all rows that has data?
but what about other questions?
For example, how to define ProcessARow correctly?
If you need the values in the Row, you need use the 'Value' Property and after do an cycle to get each value
for each row in Worksheet.rows
Values=row.Value
For each cell in Values
ValueCell=cell
next cell
next row
Unfortunately you questions are very broad however I believe the below sub routine can show you a few ways of achieving what you are after. In regards to what datatype each cell is more involved as it depends what data type you wish to compare it to however I have included some stuff to hopefully help.
sub hopefullyuseful()
dim ws as worksheet
dim rng as Range
dim strlc as string
dim rc as long, i as long
dim lc as long, j as long
dim celltoprocess as range
set ws = activeworkbook.sheets(activesheet.name)
strlc = ws.cells.specialcells(xlcelltypeLastCell).address
set rng = ws.range("A1:" & lc)
rc = rng.rows.count()
debug.print "Number of rows: " & rc
lc = rng.columns.count()
debug.print "Number of columns: " & lc
'
'method 1 looping through the cells'
for i = 1 to rc
for j = 1 to lc
set celltoprocess = ws.cells(i,j)
'this gives you a cell object at the coordinates of (i,j)'
'[PROCESS HERE]'
debug.print celltoprocess.address & " is celltype: " & CellType(celltoprocess)
'here you can do any processing you would like on the individual cell if needed however this is not the best method'
set celltoprocess = nothing
next j
next i
'method 2 looping through the cells using a for each loop'
for each celltoprocess in rng.cells
debug.print celltoprocess.address & " is " & CellType(celltoprocess)
next celltoprocess
'if you just need the data in the cells and not the actual cell objects'
arrOfCellData = rng.value
'to access the data'
for i = lbound(arrOfCellData,1) to ubound(arrOfCellData,1)
'i = row'
for j = lbound(arrOfCellData,2) to ubound(arrOfCellData,2)
'j = columns'
debug.print "TYPE: " & typename(arrOfCellData(i,j)) & " character count:" & len(arrOfCellData(i,j))
next j
next i
set rng=nothing
set celltoprocess = nothing
set ws = nothing
end sub
Function CellType(byref Rng as range) as string
Select Case True
Case IsEmpty(Rng)
CellType = "Blank"
Case WorksheetFunction.IsText(Rng)
CellType = "Text"
Case WorksheetFunction.IsLogical(Rng)
CellType = "Logical"
Case WorksheetFunction.IsErr(Rng)
CellType = "Error"
Case IsDate(Rng)
CellType = "Date"
Case InStr(1, Rng.Text, ":") <> 0
CellType = "Time"
Case IsNumeric(Rng)
CellType = "Value"
End Select
end function
sub processRow(byref rngRow as range)
dim c as range
'it is unclear what you want to do with the row however... if you want
'to do something to cells in the row this is how you access them
'individually
for each c in rngRow.cells
debug.print "Cell " & c.address & " is in Column " & c.column & " and Row " & c.row & " has the value of " & c.value
next c
set c = nothing
set rngRow = nothing
exit sub
if you want your other questions answered you will have to be more specific as to what you are trying to accomplish
While I like the solution offered by #krazynhazy I believe that the following solution might be slightly shorter and closer to what you asked for. Still, I'd use the CellType function offered by Krazynhazy rather than all the Iif I currently have in the below code.
Option Explicit
Sub AllNonEmptyCells()
Dim rngRow As Range
Dim rngCell As Range
Dim wksItem As Worksheet
Set wksItem = ThisWorkbook.Worksheets(1)
On Error GoTo EmptySheet
For Each rngRow In wksItem.Cells.SpecialCells(xlCellTypeConstants).EntireRow.Rows
Call ProcessARow(wksItem, rngRow.Row)
Next rngRow
Exit Sub
EmptySheet:
MsgBox "Sheet is empty." & Chr(10) & "Aborting!"
Exit Sub
End Sub
Sub ProcessARow(wksItem As Worksheet, lngRow As Long)
Dim rngCell As Range
Debug.Print "Cells to process in row " & lngRow & ": " & wksItem.Range(wksItem.Cells(lngRow, 1), wksItem.Cells(lngRow, wksItem.Columns.Count)).SpecialCells(xlCellTypeConstants).Count
For Each rngCell In wksItem.Range(wksItem.Cells(lngRow, 1), wksItem.Cells(lngRow, wksItem.Columns.Count)).SpecialCells(xlCellTypeConstants)
Debug.Print "Row: " & lngRow, _
"Column: " & rngCell.Column, _
"Value: " & rngCell.Value2, _
IIf(Left(rngCell.Formula, 1) = "=", "Formula", IIf(IsDate(rngCell.Value), "Date", IIf(IsNumeric(rngCell.Value2), "Number", "Text")))
Next rngCell
End Sub
Note, that you have to call the sub to call a row must also include the sheet on which a row should be processed.

Get start range and end range of a vertically merged cell with Excel using VBA

I need to find out the first cell and the last cell of a vertically merged cell..
Let's say I merge Cells B2 down to B50.
How can I get in VBA the start cell(=B2) and the end cell(=B50)?
Sub MergedAreaStartAndEnd()
Dim rng As Range
Dim rngStart As Range
Dim rngEnd As Range
Set rng = Range("B2")
If rng.MergeCells Then
Set rng = rng.MergeArea
Set rngStart = rng.Cells(1, 1)
Set rngEnd = rng.Cells(rng.Rows.Count, rng.Columns.Count)
MsgBox "First Cell " & rngStart.Address & vbNewLine & "Last Cell " & rngEnd.Address
Else
MsgBox "Not merged area"
End If
End Sub
Below macro goes through all sheets in a workbook and finds merged cells, unmerge them and put original value to all merged cells.
This is frequently needed for DB applications, so I wanted to share with you.
Sub BirlesenHucreleriAyirDegerleriGeriYaz()
Dim Hucre As Range
Dim Aralik
Dim icerik
Dim mySheet As Worksheet
For Each mySheet In Worksheets
mySheet.Activate
MsgBox mySheet.Name & “ yapılacak…”
For Each Hucre In mySheet.UsedRange
If Hucre.MergeCells Then
Hucre.Orientation = xlHorizontal
Aralik = Hucre.MergeArea.Address
icerik = Hucre
Hucre.MergeCells = False
Range(Aralik) = icerik
End If
Next
MsgBox mySheet.Name & " Bitti!!"
Next mySheet
End Sub
Suppose you merged B2 down to B50.
Then, start cell address will be:
MsgBox Range("B2").MergeArea.Cells(1, 1).Address
End cell address will be:
With Range("B2").MergeArea
MsgBox .Cells(.Rows.Count, .Columns.Count).Address
End With
You can put address of any cell of merged area in place of B2 in above code.
Well, assuming you know the address of one of the cells in the merged range, you could just select the offset from that range and get the row/column:
Sub GetMergedRows()
Range("A7").Select 'this assumes you know at least one cell in a merged range.
ActiveCell.Offset(-1, 0).Select
iStartRow = ActiveCell.Row + 1
Range("A7").Select
ActiveCell.Offset(1, 0).Select
iEndRow = ActiveCell.Row - 1
MsgBox iStartRow & ":" & iEndRow
End Sub
The code above will throw errors if the offset row cannot be selected (i.e. if the merged rows are A1 through whatever) so you will want to add error handling that tells the code if it can't offset up, the top rows must be 1 and if it can't go down, the bottom row must be 65,536. This code is also just one dimensional so you might want to add the x-axis as well.
If you want the cell references as strings, you can use something like this, where Location, StartCell, and EndCell are string variables.
Location = Selection.Address(False, False)
Colon = InStr(Location, ":")
If Colon <> 0 Then
StartCell = Left(Location, Colon - 1)
EndCell = Mid(Location, Colon + 1)
End If
If you want to set them as ranges, you could add this, where StartRange and EndRange are Range objects.
set StartRange = Range(StartCell)
set EndRange = Range (EndCell)
If you intend to loop through the merged cells, try this.
Sub LoopThroughMergedArea()
Dim rng As Range, c As Range
Set rng = [F5]
For Each c In rng.MergeArea
'Your code goes here
Debug.Print c.Address'<-Sample code
Next c
End Sub

Resources