0

I am trying to check if a value is in a certain range. If that value appears, the corresponding data to that enty is copied to another sheet. The trick is it has to be dynamically determined because the column size varies from input sheet to input sheet. In Java the hasNext() function can be used. I think that VBA's most similar function would be Sheet1.Column.End(xlup). How is the best way to determine the end of a column for the test condition of a do while loop in vba?

Pseudo example:

'This is part of a nested loop, this segment traverses the column looking for 'specified data.

Do While (!Sheets(inputSheetName).SyntaxToDetermineEndOfColumn))
     If(someCell = someValue)
          Copy values from the corresponding row to fields in newSheet
     End If
     Next r        'This increments the row within the current column
Loop
Next c             'This increments to the next column of data
Chrismas007
  • 6,085
  • 4
  • 24
  • 47
  • 1
    possible duplicate of [Error Finding Last Used cell In VBA](http://stackoverflow.com/questions/11169445/error-finding-last-used-cell-in-vba) – Chrismas007 Feb 13 '15 at 14:50
  • So then .Range("E" & .Rows.Count).End(xlUp).Row would be a solution for the SyntaxToDetermineEndOfColumn part? Where the range is specified by column "E", I am using a variable "c" as a column for the purposes of looping. I should just be able to use the variable "c" right? This is my first project using VBA. – SystemMonkey Feb 13 '15 at 14:56
  • Check out my answer below – Chrismas007 Feb 13 '15 at 14:58

3 Answers3

0

There are two parts to your question:

The first part about finding the last used row is easialy found with a quick Google: Error in finding last used cell in VBA

To loop from start to end of column, use this:

Dim ws1 as Worksheet, LastRow as Long, CurRow as Long, DataFind as String

Set ws1 = Sheets("Name of Sheet")
LastRow = ws1.Range("Column letter" & ws1.Rows.Count).End(xlUp).Row

DataFind = Inputbox("What are you looking for?")

For CurRow = 1 to LastRow
    If ws1.Range("Column Letter" & CurRow).Value = DataFind Then
        ws1.Range("Column Letter" & CurRow).EntireRow.Copy
        Sheets("Dest Sheet").Range("Whatever").PasteSpecial
    End If
Next CurRow
Community
  • 1
  • 1
Chrismas007
  • 6,085
  • 4
  • 24
  • 47
0

Say we have data like:

enter image description here

We want to find happiness in the first two columns and retrieve the column C value in that row:

Sub LookingForHappiness()
    Dim i As Long, j As Long, N As Long, h As String
    h = "happiness"
    For i = 1 To 2
        N = Cells(Rows.Count, i).End(xlUp).Row
        For j = 1 To N
            If Cells(j, i).Value = h Then
                MsgBox Cells(j, "C").Value
                MsgBox Cells(j, i).Address(0, 0)
                Exit Sub
            End If
        Next j
    Next i
End Sub
Gary's Student
  • 95,722
  • 10
  • 59
  • 99
  • Yes exactly like this! I have an entire sheet as input and I have to find data that is within the same row as a character x. So I find X and copy the data to a new sheet. I have my looping variables as Integers, I don't want to sound noobish here, but what would be the advantage of using a long type for this? Also, What if there is a legend of formatting at the bottom. Is there a good way of pulling that out? Like running the n test, deleting the standardized legend. Running the n test again? – SystemMonkey Feb 13 '15 at 15:10
  • I use **Long** rather than **Integer** because **Integer** can handle "small" numbers only. If there is material at the bottom of the worksheet that you wish to exclude from the search, then use something like **N-7** or something similar in the *J-loop.* – Gary's Student Feb 13 '15 at 15:17
  • Thank you so much, this was very helpfull! I used integer here as the particular type of data I have never exceeds around 350 records per column for this particular input. That is a good point for the new sheet variables though as depending on the number of column, I could run into issues. N-7 seems so obvious logically! I am just getting a little overwhelmed by the new syntax. Thanks again! – SystemMonkey Feb 13 '15 at 15:30
0

You might find this useful: http://support.microsoft.com/kb/830287

But what I personally do in this situation involves a bit more code, but is flexible and fast. First create a class and call it "RangeInfo". Then past this:

Option Explicit

Private Type Properties
    Intialized As Boolean
    Object As Excel.Range
    RowBottom As Long
    RowCount As Long
    RowTop As Long
    ColumnLeft As Long
    ColumnCount As Long
    ColumnRight As Long
End Type

Private this As Properties

Public Property Get Initialized() As Boolean
    Initialized = this.Intialized
End Property

Public Property Get Object() As Excel.Range
    Set Object = this.Object
End Property

Public Property Get ColumnLeft() As Long
    ColumnLeft = this.ColumnLeft
End Property

Public Property Get ColumnCount() As Long
    ColumnCount = this.ColumnCount
End Property

Public Property Get ColumnRight() As Long
    ColumnRight = this.ColumnRight
End Property

Public Property Get RowBottom() As Long
    RowBottom = this.RowBottom
End Property

Public Property Get RowCount() As Long
    RowCount = this.RowCount
End Property

Public Property Get RowTop() As Long
    RowTop = this.RowTop
End Property

Public Sub Initialize(ByRef rng As Excel.Range)
    With this
        Set .Object = rng
        .RowTop = rng.row
        .RowCount = rng.Rows.Count
        .RowBottom = .RowTop + .RowCount - 1&
        .ColumnLeft = rng.Column
        .ColumnCount = rng.Columns.Count
        .ColumnRight = .ColumnLeft + this.ColumnCount - 1&
        .Intialized = True
    End With
End Sub

Public Sub Clear()
    Dim emptyProperties As Properties
    this = emptyProperties
End Sub

Private Sub Class_Terminate()
    Set this.Object = Nothing
End Sub

Then for your code, use this:

Option Explicit

Public Sub Example()
    'Set these as needed:
    Const sheetName As String = "MySheet"
    Const columnNumber As Long = 2&
    Const criteria As String = "*foo#"

    Dim wsIn As Excel.Worksheet
    Dim wbOut As Excel.Workbook
    Dim wsOut As Excel.Worksheet
    Dim ri As RangeInfo
    Dim rowIn As Long
    Dim rowOut As Long
    Dim col As Long


    Set wbOut = Excel.Workbooks.Add
    Set wsOut = wbOut.Worksheets(1)
    Set wsIn = Excel.Worksheets(sheetName)
    Set ri = New RangeInfo
    ri.Initialize wsIn.UsedRange
    rowOut = 1&
    With ri
        For rowIn = .RowTop To .RowBottom
            If wsIn.Cells(rowIn, columnNumber) Like criteria Then
                rowOut = rowOut + 1&
                For col = .ColumnLeft To .ColumnRight
                    wsOut.Cells(rowOut, col).Value = wsIn.Cells(rowIn, col).Value
                Next
            End If
        Next
    End With

End Sub
Pillgram
  • 804
  • 6
  • 11
  • 1
    Thanks for this idea! It definitely looks a lot more familiar to what I am accustomed to. I like the concept of creating a class; as I will be using this type of process in slightly different ways. Unfortunately, I think for the particulars of my case, a procedural approach is better. I will definately keep this in mind in the future! – SystemMonkey Feb 13 '15 at 15:44