Question

I have a legacy spreadsheet which has worksheets for each person in the team.
Worksheets have multiple columns, the columns I'm interested in are A and B, A has a job name and B has a total of hours that person has worked on that job.

In another sheet (called "Consolidation"), I have column A which also has the job name, and column H where a total of hours worked by all people o the project need to be placed.

Currently, I have the following code:

'Modified from: http://www.rondebruin.nl/win/s9/win006.htm
Private Function Find_First(ByVal sht As Integer, ByVal cell As String)
    Dim FindString As String
    Dim Rng As Range
    FindString = Sheets(sht).Range(cell).value
    If Trim(FindString) <> "" Then
        With Sheets(sht).Range("A:A")
            Set Rng = .Find(What:=FindString, _
                            After:=.Cells(.Cells.Count), _
                            LookIn:=xlValues, _
                            LookAt:=xlWhole, _
                            SearchOrder:=xlByRows, _
                            SearchDirection:=xlNext, _
                            MatchCase:=False)
            If Not Rng Is Nothing Then
                Find_First = Rng
            End If
        End With
    End If
End Function

Public Function getSummary(ByVal myCell As Range)
    Dim total As Integer

    For i = 1 To Sheets.Count
        ' Iterate over all the sheets

        If Sheets(i).Name = "Consolidation" Then
            ' If the sheet is "Consolidation" then skip to next element
            GoTo NextIteration
        End If

        Dim job As Range
        Dim value As Range

        Set job = Find_First(i, myCell)
        Set value = job.Offset(0, 1).value

        total = total + value

NextIteration:
    Next

    getSummary = total
End Function

I call it from column H3 using =getSummary(A3). H3 then equals #VALUE!, and I've no idea why...As you can probably tell from the code, I'm no VBA expert, and I've no idea where to begin as there doesn't seem to be much in the way of debugging tools...

UPDATE: With thanks to David and CodeJockey, I've got a few functions that work exactly as I need them to:

'Modified from: http://www.rondebruin.nl/win/s9/win006.htm
Private Function FindFirst(ByVal sht As Integer, ByVal cell As String) As Range
    Dim FindString As String
    Dim Rng As Range
    FindString = Sheets("Consolidation").Range(cell).value
    If Trim(FindString) <> "" Then
        With Sheets(sht).Range("A:A")
            Set Rng = .Find(What:=FindString, _
                            After:=.Cells(.Cells.Count), _
                            LookIn:=xlValues, _
                            LookAt:=xlWhole, _
                            SearchOrder:=xlByRows, _
                            SearchDirection:=xlNext, _
                            MatchCase:=False)
            If Not Rng Is Nothing Then
                Set FindFirst = Rng
            End If
        End With
    End If
End Function

Private Function getData(ByVal myCell As Range, ByVal offset As Integer)
    Dim total As Integer
    total = 0

    For i = 1 To Sheets.Count
        ' Iterate over all the sheets

        If Sheets(i).Name = "Consolidation" Then
            ' If the sheet is "Consolidation" then skip to next element
            GoTo NextIteration
        End If

        Dim job As Range
        Dim value As String

        Set job = FindFirst(i, myCell.Address)
        If Not job Is Nothing Then
            value = job.offset(0, offset).value
            If Not IsEmpty(value) And IsNumeric(value) Then
                total = total + value
            End If
        End If

NextIteration:
    Next

    getData = total
End Function

Function getBurnHours(ByVal myCell As Range)
    Application.Volatile
    getBurnHours = getData(myCell, 1)
End Function

Public Function getBurnDays(ByVal myCell As Range)
    Application.Volatile
    getBurnDays = getData(myCell, 2)
End Function

Public Function getActualHours(ByVal myCell As Range)
    Application.Volatile
    getActualHours = getData(myCell, 3)
End Function

Public Function getActualDays(ByVal myCell As Range)
    Application.Volatile
    getActualDays = getData(myCell, 4)
End Function
Was it helpful?

Solution

myCell is a Range object, but the function Find_First is expecting a String argument.

So you should change this:

Set job = Find_First(i, myCell)

To this:

Set job = Find_First(i, myCell.Address)

You will also need to change the return statement so that the return value matches the type of data expected in the job variable (Range), you need the Set keyword in this assignment:

Set Find_First = Rng

Or, you need to change the declared type of job to something other than Range object. I am not really sure what you expect to return, but because your data types are all wack, it is difficult to recommend a precise solution.

And likewise, your declaration of Value as Range object cannot accept job.Offset(0, 1).Value (which returns a string), without raising a mismatch error. So again, you either need to change the declaration of this variable or change the assignment of the object.

Otherwise, this may prove useful:

http://www.cpearson.com/excel/DebuggingVBA.aspx

OTHER TIPS

The function Find_First(sht, cell) is returning the value in "Rng", NOT the object itself. To return the object, use the "Set" operator. See the edit below:

If Not Rng Is Nothing Then
     Set Find_First = Rng
End If

This is allowed because your private function returns a Variant, not a Range. For clarity, I would also change this:

Private Function Find_First(ByVal sht As Integer, ByVal cell As String)

to this:

Private Function Find_First(ByVal sht As Integer, ByVal cell As String) as Range
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top