Loopy Loop through Range in Excel VBA - vba

I am looping through a range in Excel VBA. I have an IF-Then that checks to see if the a cell contains a number. I then want the address of the cell that contains the number. The problem is my code returns the first cell with a number over and over.
For Each Row in Room.Rows
If IsNumber(Row.Cells(,1)) then
x = (Row.cells(,1))
End If
Next Row

For Each Row in Room.Rows
If WorksheetFunction.IsNumber(range("A" & Row.row)) then
x = range("A" & Row.row).address
// do stuff with x
End If
Next Row

1) don't use variable names that will confuse people (row)
2) in the for each loop example, you don't need to add the .rows ,
considering your named variable 'row' is a row type.
3) Declare all your variables
4) i changed the code with an other approach :
Dim R as Long
Dim Rg as Range
Dim x as String
For R=1 to Room.rows.count
set Rg= Room.cells(r,1)
If IsNumeric(Rg) then
x = Rg.address
// do stuff with x
End If
Next R
set rg= nothing

Related

Loop with multiple Ranges

Im trying to write a code which determines whether certain cells are empty or not and then returns a set string.
To go in detail; I was hoping for the code to look into cell B2, determine if it is empty, then go to C2 and determine if it is non-empty. If both were correct in cell B2 it would then input "Correct" and move on in the range. However, my code doesnt seem to work because it just inputs "Correct" in every cell in the loop range.
I have posted my code below; any help would be much appreciated.
Sub Fill_Rows()
Dim X As Range
Let Y = Range("C2")
For Each X In Range("B2:B5000")
If X = "" And Y <> "" Then
X = "Correct"
End If
Y = Y + 1
Next X
End Sub
If you meant to check by each row like (B2 and C2) then (B3 and C3), then you could do it like this.
Sub Fill_Rows()
Dim iRow As Long
For iRow = 2 To 5000
If Cells(iRow, "B").Value = vbNullString And Cells(iRow, "C").Value <> vbNullString Then
Cells(iRow, "B").Value = "Correct"
End If
Next iRow
End Sub
Alternative
Added two solutions:
[1] an example code as close as possible to yours and
[2] an alternative using a datafield array to demonstrate a faster way for bigger data sets.
[1] Example Code close to yours
There is no need to use a second variable Y, all the more as apparently you left it undeclared, which always can cause issues (type mismatches, no range object etc.).
So always use Option Explicit in the declaration head of your code module to force yourself to declare all variable types you are using.
Now you can simply use an offset of 1 column to the existing cell to check the neighbouring cell, too.
Option Explicit ' declaration head of your code module (obliges to declare variables)
Sub Fill_RowsViaRangeLoop()
Dim X As Range, ws As Worksheet
Set ws = ThisWorkbook.Worksheets("MySheet") ' << replace with your sheet name
For Each X In ws.Range("B2:B5000")
If X = "" And X.Offset(0, 1) <> "" Then ' column offset 1 checks next cell in C
X = "Correct"
End If
Next X
End Sub
[2] Example Code using a datafield array
Looping through a bigger range isn't very fast, you can speed up your procedure by
assigning your range values to a variant datafield array v, loop through the received array items correcting found items in column 1 and write it back to sheet.
Option Explicit ' declaration head of your code module (obliges to declare variables)
Sub Fill_RowsViaArray()
Dim v As Variant, i As Long, ws As Worksheet
Set ws = ThisWorkbook.Worksheets("MySheet") ' << replace with your sheet name
' Assign values to a 2-dim array
v = ws.Range("B2:C5000") ' or better: v = ws.Range("B2:C5000").Value2
' Check criteria looping over all rows (=first array dimension)
For i = 1 To UBound(v) ' data field arrays are one-based, i.e. they start with 1
If v(i, 1) = vbNullString And v(i, 2) <> vbNullString Then v(i, 1) = "Correct"
Next i
' Write edited array back to original range (adapt the range size to the array boundaries in both dimensions)
ws.Range("B2").Resize(UBound(v, 1), UBound(v, 2)) = v
End Sub
Further Notes
It's good use to fully qualify your sheet or range references (see e.g. object variable ws)
Each array item is identified by a row and a column index.
As such a datafield array is one based (start indices are 1), the first item in row 1 and column 1 will be referred by v(1,1), in col 2 by v(1,2).
In order to count the number of row items you check the upper boundary of its first dimension) via UBound(v,1) or even shorter via Ubound(v)
In order to count the number of columns you check the upper boundary of its second dimension) via UBound(v,2) (here the argument 2 is necessary!)
A comparation using vbNullString can be preferred in coding to "" as it takes less memory (c.f. #PEH 's answer) .

Excel VBA: How to find first empty row within a Table for a Loop routine?

I reformatted a range of Sheets("Records") in a workbook as a Table (named "RecordsTable") to make it easier to do INDEX(MATCH,MATCH) functions for generating reports.... but now I screwed up my looping routine for filling that range from the input on Sheets("FORM").
It used to be:
Set r = Sheets("Records").Range(A & Rows.Count).End(x1Up).Offset(1, 0)
i = 0
For Each c In Range("dataRange")
'dataRange is a list of cells to reference from the FORM input sheet
r.Offset(0, i).Value = Worksheets("FORM").Range(c)
i = i + 1
Next
However this code is now selecting the first row at the END of "RecordsTable" (row 501, as I defined 500 rows in my table) and inserting the data there.
I tried to change it to this:
Set r = Sheets("Records").ListObjects("RecordsTable").DataBodyRange("A" & Rows.Count).End(x1Up).Offset(1, 0)
i = 0
For Each c In Range("dataRange")
r.Offset(0, i).Value = Worksheets("FORM").Range(c)
i = i + 1
Next
But this code is still selecting row 501 and making that row part of "RecordsTable".
How can I properly Set "r" to = the first empty row in "RecordsTable"?
For reference, Column "A" in "RecordsTable" has the header [INV #]. Also, when I step into the "Set r = ..." line, Rows.Count is returning a value of 1million+ (ie, total rows on the sheet) - if I understand this correctly, I want it to return a value of 500 (ie, total rows in table) - is that correct?
EDIT
"dataRange" is a single column list of cell references (I do have them labeled in column B, as #chrisneilsen suggest:
A
J6
Y6
J8
J10
Y8
etc.
They are the cells on Sheets("FORM") that I need to pull data from and populate into my table, in the order indicated in "dataRange".
Assuming you really have a Table, adding data to a Table (ListObject) using it's properties and methods:
Sub Demo()
Dim lo As ListObject
Dim c As Range
Set lo = Worksheets("Records").ListObjects("RecordsTable")
For Each c In Sheets("V").Range("dataRange")
If Not lo.InsertRowRange Is Nothing Then
lo.InsertRowRange.Cells(1, 1) = Sheets("FORM").Range(c)
Else
lo.ListRows.Add.Range.Cells(1, 1) = Sheets("FORM").Range(c)
End If
Next
End Sub
Note: looping a range on sheet V and using that as a pointer to data on sheet FORM, copied from your answer - I'm assuming you know what you are doing here
Based on OP comment, adding data a single new row
Sub Demo()
Dim lo As ListObject
Dim c As Range, TableRange As Range
Dim i As Long
Set lo = Worksheetsheets("Records").ListObjects("RecordsTable")
If Not lo.InsertRowRange Is Nothing Then
Set TableRange = lo.InsertRowRange
Else
Set TableRange = lo.ListRows.Add.Range
End If
i = 1
For Each c In Sheets("V").Range("dataRange")
TableRange.Cells(1, i) = Sheets("FORM").Range(c)
i = i + 1
Next
End Sub
Note, this assumes that the order of the table columns is the same as the order of dataRange. It may be better to include table field names in dataRange to avoid any mismatch issues
As mentioned in updated OP, if column labels are in the next column, replace the For loop with this (and add Dim r as Range, col as long to declarations)
For Each c In Sheets("V").Range("dataRange")
If Not c = vbNullString Then
Set r = Worksheets("FORM").Range(c.Value)
col = lo.ListColumns(c.Offset(, 1).Value).Index
TableRange.Cells(1, col) = r.Value
End If
Next

Issue with looping through a column in excel looking for cells with a particular value

What i am trying to do is look into another excel sheet and pick out information from the rows that have the same string as another in a different sheet. I need to loop though the list and pick out only a few values from the rows. I am still a long shot from achieving this so first im just looking into the sheet1 trying to compare it to the other cell in sheet2.If they have the same value i want to pick out certain cell value in the row where they find the same value and then put them into the other sheet. Apologies if this does not make sense. Here is my code so far. Also i get an error 'object defined when i run the code. When i debug its the line with the if statement thats going wrong
Sub Awesome_macro()
Dim x As Integer
Dim Counter As Integer
' Set numrows = number of rows of data.
NumRows = Range("H15", Range("H15").End(xlDown)).Rows.Count
' Select cell a1.
Range("H16").Select
' Establish "For" loop to loop "numrows" number of times.
For x = 1 To NumRows
If StrComp(Sheets("Sheet1").Cells(H, 15).Value, Sheets("Sheet2").Cells(A, 1).Value) = 0 Then
Sheets("Sheet1").Range("D15").Copy Destination:=Sheets("Sheet2").Range("B2")
End If
' Selects cell down 1 row from active cell.
ActiveCell.Offset(1, 0).Select
Next
End Sub
Try following piece of code:
Value2Find = Sheets("Sheet2").Cells(A, 1).Value
Row_Num = Sheets("Sheet1").Range("A:A").Find(What:=Value2Find, LookIn:=xlValues).Row
I kind of found a way to to it but its not looping through correctly
Sub Awesome_macro()
Dim x As Integer
Dim Counter As Integer
' Set numrows = number of rows of data.
NumRows = Range("H15", Range("H15").End(xlDown)).Rows.Count
' Select cell a1.
Range("H16").Select
' Establish "For" loop to loop "numrows" number of times.
For x = 1 To NumRows
If (Sheets("Sheet1").Range("H15").Value = Sheets("Sheet2").Range("A1").Value) Then
Sheets("Sheet1").Range("D15").Copy Destination:=Sheets("Sheet2").Range("B3")
End If
' Selects cell down 1 row from active cell.
ActiveCell.Offset(1, 0).Select
Next
End Sub
Its printing something into the sheet2 now so the comparing the values and printing on the page works. just need to figure out how to loop it properly

How to get the value of a range within a range

So I need to extract information from a sheet with only certain values. From about 550 rows down to 50 which are spread across the entire sheet.
So I used autofilter for that. Now I only see the rows which match to my criteria but how can I get the values of a specific range from?
This far I came:
I know that I have to use
RangeINamed.SpecialCells(xlCellTypeVisible)
to work with only the visible information.
It worked for getting the starting and last row
startRow = bulkbatchRange.SpecialCells(xlCellTypeVisible).row
endRow = startRow + bulkbatchRange.SpecialCells(xlCellTypeVisible).rows.Count
But now I need to get the value of a specific column, I want to use a For loop so I can loop through all visible rows.
So I tried to do
RangeINamed.SpecialCells(xlCellTypeVisible).range("U" & rowNumber).value
That didn't work it gave me nothing. Now I'm rather clueless so does someone maybe know how I get the value of that row in column U in RangeINamed?
Thank you
You can always retrieve the value in a specific cell like U10 with:
Range("U10").Value
whether the row is hidden or not.
EDIT#1:
Here is a little example that loops down thru column A of an AutoFiltered table. It looks for the third visible row (not including the header row):
Sub GoDownFilter()
Dim rLook As Range, r As Range
Set rLook = Intersect(ActiveSheet.UsedRange, Range("A:A").Cells.SpecialCells(xlCellTypeVisible))
rLook.Select
K = 0
For Each r In rLook
If K = 3 Then
r.Select
MsgBox "The third visible row has been selected"
Exit Sub
End If
K = K + 1
Next r
End Sub
I think you need to choose if you want to get a specific cell like:
Range("U10").Value
Or a relative cell using something like
RangeINamed.SpecialCells(xlCellTypeVisible)(2,3).Value
Or
RangeINamed.SpecialCells(xlCellTypeVisible)(2,3).Address 'To see if you are getting it right
EDIT:
A complete code to Filter and Iterate.
Sub Filter()
Dim tableRange As Range, var, actualRow As Integer, lastRow As Integer
Set tableRange = Range("PUT_THE_TABLE_RANGE_HERE")
' Filter
With tableRange
Call .AutoFilter(5, "SPECIFIC_FILTER")
End With
Set f = tableRange.SpecialCells(xlCellTypeVisible)
With tableRange
Call .AutoFilter(5)
End With
For Each var In f.Cells.Rows
actualRow = var.Row
If actualRow <> 1 Then
' Do something
End If
Next
End Sub

vba incrementing a range's row

this should be a really quick question.
Is there any way to increment the value of a cell.Row?
For example, can I say something like usedCell.Row = usedCell.Row + 1?
That particular format doesn't work, but is there another way to increase the row by 1?
I believe cell.Offset(1,0) is what you are looking for.
The Row and Column properties of a cell (i.e. Range) are read-only so you can't increment them directly.
If you want to move through the cells in column A then iDevlop's answer works fine. An alternative method is to use the Cells method of the Worksheet object. Example code to write the word "hello" into every cell in column A from row 1 to 100:
Dim lRow As Long
For lRow = 1 To 100
Worksheets("Sheet1").Cells(lRow, 1).Value = "hello"
Next lRow
As you can see in the example, the Cells method takes the row number as the first parameter and the column number as the second parameter.
For the simple case of dealing with cells in the same column, you could also use the Range property of the Worksheet object and construct the actual address - e.g. A39 - each time:
Dim lRow As Long
For lRow = 1 To 100
Worksheets("Sheet1").Range("A" & lRow).Value = "hello"
Next lRow
Have you considered using
Dim c as Range
For Each c in Range("a:a")
...
Next c
?
You may be looking for
Set rng = rng.Resize(RowSize, ColumnSize)
In your case specifically
Dim rng_usedCells As Range
Set rng_usedCells = ActiveSheet.Range("A1:B10")
ActiveSheet.Range("D2").Value = rng_usedCells.Rows.Count
ActiveSheet.Range("E2").Value = rng_usedCells.Columns.Count
Set rng_usedCells = rng_usedCells.Resize(3, 4)
ActiveSheet.Range("D3").Value = rng_usedCells.Rows.Count
ActiveSheet.Range("E3").Value = rng_usedCells.Columns.Count