Macro to select first non-empty cell in entire sheet - vba

Suppose there is only one non-empty cell in a sheet and you want a macro to find it. So far I have the following code but am struggling to adjust it so it searches all columns, not only one:
Sub FirstNonEmpty()
Dim ws As Worksheet
Set ws = ActiveSheet
For Each cell In ws.Columns(1).Cells
If Not IsEmpty(cell) = True Then cell.Select: Exit For
Next cell
End Sub
Perhaps there is a way to use a variable equal to all columns instead of "1" in "ws.Columns(1).Cells"?

You could use the top formulation if the non-blank cell does not contain a formula, or use xlcelltypeformulas if it's a formula. If you know there is a non-blank, you don't need the On Error. In fact if there is definitely only one you don't need the (1) either.
On Error Resume Next
ActiveSheet.Cells.SpecialCells(xlCellTypeconstants)(1).Select
'or
'ActiveSheet.Cells.SpecialCells(xlCellTypeformulas)(1).Select

Or you may give this a try...
Dim Rng As Range
Set Rng = Cells.Find(what:="*", LookIn:=xlValues)
If Not Rng Is Nothing Then
Rng.Select
End If

You can change the For statement to:
For Each cell In ws.UsedRange.Cells
which has the benefit of not scanning the rows/columns at the end of the worksheet as well.

Related

VB vlookup in different sheet for certain values

can you please help me with a vlookup in a different sheet only for certain values?
I have tried for each, for i, different if's and so on.
I need the vba to bring in Sheet2 values from a Sheet1, but only for rows that have the value "De rediscutat" in a different column in Sheet2.
Below you have the code i wrote for this function:
Dim result As String
Dim Sheet2 As Worksheet
Set Sheet2 = ActiveWorkbook.Sheets("Sheet2")
Set MyRange = Range("X2:X800")
If MyRange = "De rediscutat" Then
Worksheets("Sheet2").Range("N2:N694").Formula = Application.WorksheetFunction.VLookup(Sheet2.Range("I2:I694"), Sheet1.Range("G2:M500"), 7, False)
End If
End Sub```
Thanks!
You will need a loop to do this. Your code also has much redundancy. This will hopefully get you started:
Dim cel As Range, myrange As Range
Set myrange = Sheet2.Range("X2:X800")
For Each cel In myrange
If cel.Value = "De rediscutat" Then
'Grab whichever value you need and put it where you need it
End if
next cel
I suggest using Cel.Row to get the row number of the current cell in the loop, or Cel.Offset(,) to get to a cell on the same row.
For Each and For i will both work for looping through MyRange but you have not included either in your code.
The problem may not have been your loop, but rather the way you test the cell. If MyRange = "De rediscutat" will only work when MyRange` is a single cell.
If you Dim cell As Range recreate a For Each cell In MyRange loop and use `If cell = "De rediscutat" then it should work.

How to loop through only the non-empty cell in a column in an excel sheet via VBA?

According to this website.
I think this should work:
Dim cell As Range
For Each cell In xxxSheet.Range("B:B").SpecialCells(xlCellTypeFormulas, xlNumbers)
'Do sth.
Next
which does not work. Is there something missing?
This should be working solution:
For Each cell In xxxSheet.Range("B:B")
If Not IsEmpty(cell) Then
'do sth
End If
Next
Also, if you want to loop until last filled cell, you could use following:
xxxSheet.Range("B1:B" & Cells(Rows.Count, 2).End(xlUp).Row)
instead of
xxxSheet.Range("B:B")
It does not work, because you do not have formulas on column B. Put some formulas and some constants and try this:
Option Explicit
Public Sub TestMe()
Dim myCell As Range
Dim myRange As Range
Set myRange = Worksheets(1).Columns("B:B").SpecialCells(xlCellTypeFormulas, xlNumbers)
For Each myCell In myRange
Debug.Print myCell.Address
Next
Set myRange = Worksheets(1).Columns("B:B").SpecialCells(xlCellTypeConstants, xlNumbers)
For Each myCell In myRange
Debug.Print myCell.Address
Next
End Sub
The first loop would print the addresses of the formula cells, the second the addresses of the constants.
This is the ozgrid explanation about SpecialCells:
http://www.ozgrid.com/VBA/special-cells.htm
The problem is SpecialCells(xlCellTypeFormulas, xlNumbers) is returning only cells with formulas that make numbers (ie. =1+2).
To keep things efficient, you only need to check up to the last filled row
For Each cell In xxxSheet.Range("B1", Cells(Rows.Count, 2).End(xlUp))
If Not IsEmpty(cell) Then
'Do sth.
End If
Next
If you really want you can use SpecialCells() to have a range containing no blanks to loop through. If you only have formulas or only constants, you could use SpecialCells(xlFormulas) or SpecialCells(xlConstants) respectively, but for a more general use case you will have to do do a combination of the two.
Dim cell As Range
Dim searchRange As Range
' SpecialCells errors when there aren't cells instead of giving a useful value
On Error Resume Next
Set searchRange = xxxSheet.Range("B:B").SpecialCells(xlFormulas)
Set searchRange = xxxSheet.Range("B:B").SpecialCells(xlConstants)
Set searchRange = Union(xxxSheet.Range("B:B").SpecialCells(xlConstants), _
xxxSheet.Range("B:B").SpecialCells(xlFormulas))
On Error GoTo 0
If searchRange Is Not Nothing Then ' Only continue if no blanks
For Each cell In searchRange
'Do sth.
Next
End If

VBA clear cell range based on a certain condition

This problem may seems pretty simple but I have been dealing with it for 2 days now and cant get it done. I searched other forums to see if they have this same problem but didnt find close to tyhis one.
So I have range K:T starting from row 2 and need to clear the cells that contains #N/A. I wrote the code below but cant seem to make it work.
Sub Clear_cells()
Dim rng As Range, i As Integer
'Set the range to evaluate to rng.
Set rng = Range("K:T")
'Loop backwards through the rows
'in the range that you want to evaluate.
For i = rng.Rows.count To 1 Step -1
'If cell i in the range contains an "N/A", delete cell content
If rng.Cells(i).Value = "#N/A" Then rng.Cells(i).CellRange.ClearContents (1)
Next
End Sub
If your cells contain an error value (i.e. #N/A) rather than the string "#N/A" then you need to check for an error value instead of checking for a string.
Replace
For i = rng.Rows.count To 1 Step -1
'If cell i in the range contains an "N/A", delete cell content
If rng.Cells(i).Value = "#N/A" Then rng.Cells(i).CellRange.ClearContents (1)
Next
with
Dim cel As Range
For Each cel in rng
If IsError(cel.Value) Then
If cel.Value = CVErr(xlErrNA) Then cel.ClearContents
End If
Next
or, if you want to check for all error conditions (such as #DIV/0!), just use
Dim cel As Range
For Each cel in rng
If IsError(cel.Value) Then cel.ClearContents
Next
use the function isna to check for #N/A
If Application.WorksheetFunction.IsNa(rng.Cells(i)) Then rng.Cells(i).CellRange.ClearContents (1)

VBA removing rows from a spreadsheet if cells contain a certain string

I am very new to VBA. I am trying to isolate a particular customers transactions on a spread sheet.
Column "A" contains the Customer payment method (prepaid or various other methods). Column "D" contains the customer we are shipping too, Column "L" contains the customer we are shipping from.
If the cell in column "A" has 'prepaid' I want to search column "D" for the customer name (jaba). I will then delete all rows which do not contain this customer. IF the cell in column "A" is not 'prepaid' I want it to search column "L" for the customer name, and delete all rows which do not contain this string. When I run the code provided below I get an 1004 error on the following script 'If cell3.Find(ContainWord) Is Nothing Then'. Any help would be much appreciated.
Sub DoNotContainClearCells()
Dim rng As Range
Dim rng2 As Range
Dim rng3 As Range
Dim cell As Range
Dim cell2 As Range
Dim cell3 As Range
Dim ContainWord As String
'What range do you want to search?
Set rng = Range("A:A")
Set rng2 = Range("D:D")
Set rng3 = Range("L:L")
'What phrase do you want to test for?
ContainWord = "jaba"
For Each cell In rng
If cell.Value = "prepaid" Then
'Loop through each cell in range and test cell contents
For Each cell2 In rng2.Cells
If cell2.Find(ContainWord) Is Nothing Then EntireRow.Delete
Next cell2
Else
'Loop through each cell in range and test cell contents
For Each cell3 In rng3.Cells
If cell3.Find(ContainWord) Is Nothing Then EntireRow.Delete
Next cell3
End If
Next
End Sub
Without discussing the logic of your code, which is not part of the question, I can tell you that the
Run-time error '1004': Object required
in this line:
If cell3.Find(ContainWord) Is Nothing Then EntireRow.Delete
is because the EntireRow.Delete is missing a range (see Range.EntireRow Property (Excel))
Solution: Replace these lines:
If cell2.Find(ContainWord) Is Nothing Then EntireRow.Delete
If cell3.Find(ContainWord) Is Nothing Then EntireRow.Delete
with these:
If cell2.Find(ContainWord) Is Nothing Then cell2.EntireRow.Delete
If cell3.Find(ContainWord) Is Nothing Then cell3.EntireRow.Delete
Suggest to always have at the top of the modules\classes\userforms:
Option Explicit
This would have given a Compile error: Variable not defined highlighting the error earlier at compiling time (see Option Explicit Statement)

Loops in VBA? I want to use a loop to select and copy till last cell

I am trying to select each consecutive cell in Row K (starting from Range K1), and for each cell going down, copy the value and paste it into Cell M10. However, the way the macro is written currently, the macro is selecting the cell right below the last cell in Range K, and is thus copying a blank into M10. Instead, I want the loop to work down one cell at a time. I want to select one cell at a time and copy it, i.e. the Loop will select K1 and copy it to M10, then select K2 and copy it to M10, etc, and then have the loop stop after the last cell of Range K.
Can anyone please help me out on this?
Sub test()
lastcell = Range("K" & Cells.Rows.Count).End(xlUp)
Range("K2").Select
Do
ActiveCell.Offset(1, 0).Select
Selection.Copy
Range("M10").Select
Selection.PasteSpecial
Application.Run ("Second Macro")
Loop Until IsEmpty(ActiveCell.Value)
End Sub
You can loop through column K using the small script below:
Option Explicit
Sub LoopThroughColumnK()
Dim LastRowInColK As Long, Counter As Long
Dim SourceCell As Range, DestCell As Range
Dim MySheet As Worksheet
'set references up-front
Set MySheet = ThisWorkbook.Worksheets("Sheet1")
With MySheet
LastRowInColK = .Range("K" & .Rows.Count).End(xlUp).Row
Set DestCell = .Range("M10")
End With
'loop through column K, copying from cells(counter, 11) to M10
With MySheet
For Counter = 1 To LastRowInColK
Set SourceCell = .Range("K" & Counter)
SourceCell.Copy Destination:=DestCell
'call MyMacro below
'... doing cool MyMacro stuff
Next Counter
End With
End Sub
To summarize what's happening, we:
Assign a worksheet variable to make sure we're working on the right sheet
Assign easy-to-read and reference variables for the last row and cell M10
Loop through the range in question, copying and pasting from Kn to M10
This technique also avoids using .Select, a common source of run-time errors. Here's an AMAZING post outlining lots of ways to NOT use .Select and .Activate: How to avoid using Select in Excel VBA macros
Edit: The refactoring I described in my comment above could be implemented without too much struggle. Let's break the whole problem into two bite-size chunks:
Get all the occupied cells in column K and save them as a Range
Running your secondary macro, which was keyed off cell M10, for each Cell in the Range we saved in step #1 above. We'll call the secondary macro MyOtherMacro for now
Let's get after it. Sunday Funday y'all! The code below is heavily-commented to explain what's happening in each function and step:
Option Explicit
Sub DoWork()
Dim MySheet As Worksheet
Dim ColKRange As Range
'set the worksheet we want to work on, in this case "Sheet1"
Set MySheet = ThisWorkbook.Worksheets("Sheet1")
'get the range of occupied cells in col K
Set ColKRange = OccupiedRangeInColK(MySheet)
'kick off the other macro using the range we got in the step above
Call MyOtherMacro(ColKRange)
End Sub
DoWork (above) is a "controller"-type script. All it does is kick off the other two functions we have written below, OccupiedRangeInColK and then, one step later, MyOtherMacro.
'this function returns a range object representing all
'the occupied cells in column K, starting at row 1 and ending
'at the last occupied row (in column K)
Public Function OccupiedRangeInColK(TargetSheet As Worksheet) As Range
Dim LastRow As Long
'check for unassigned worksheet object, return nothing if that's the case
If TargetSheet Is Nothing Then
Set OccupiedRangeInColK = Nothing
End If
With TargetSheet
LastRow = .Range("K" & .Rows.Count).End(xlUp).Row
Set OccupiedRangeInColK = .Range(.Cells(1, 11), .Cells(LastRow, 11))
End With
End Function
Cool -- descriptive names are a great thing when it comes to scripting. OccupiedRangeInColK (above) takes a Worksheet, then returns the occupied Range from column K.
'this function is a shell to be populated by #polymorphicicebeam
Public Function MyOtherMacro(TargetRange As Range)
Dim Cell As Range
'check for an empty range, exit the function if empty
If TargetRange Is Nothing Then Exit Function
'loop through all the cells in the passed-in range
For Each Cell In TargetRange
'Do cool stuff in here. For demo purposes, we'll just
'print the address of the cell to the screen
MsgBox (Cell.Address)
Next Cell
End Function
Finally, MyOtherMacro (above) is where you get to add your own magic. I built a "shell" function for you, which simply prints the address of the cell in question with a MsgBox. You can add your own logic where indicated inside the For Each Cell In TargetRange loop. Woo!