2013-03-28 22 views
5

當我打電話從Excel的功能(在細胞):爲什麼我的電子表格函數的行爲與從代碼中調用時行爲不同?

=allVlookup(O24,A:D,3,"") 

VS通過VBA

MsgBox allVlookup(Range("O24"), Range("A:D"), 3, "") 

我得到不同的結果。當從Excel中調用時,我只獲得第一個匹配,但是當從具有相同參數的vba測試子集調用時(除了將Range添加到允許子運行的參數外),我會得到完整的結果(不止一個) 。

我使用的功能是:

Public Function allVlookup(lookupRange As Range, tableRange As Range, colIndex As Integer, Optional delimiter As String = "") As String 

    Dim c As Range 
    Dim firstAddress As String 
    'MsgBox tableRange.Address ' this is correct 
    'With Sheets(4).Range("A1:C12").Columns(1) 
    'With Range("A1:C12").Columns(1) 

    'this doesn't allow things to work right either (???) 
    'Set tableRange = Range("A:D") 
    'Set lookupRange = Range("O24") 

    'search only the first column for matches 
    With tableRange.Columns(1) 
     Set c = .Find(what:=lookupRange.Value, LookIn:=xlValues) 

     If Not c Is Nothing Then 

      firstAddress = c.Address 

      Do 
       'add the delimiter 
       If (allVlookup <> "") Then 
        allVlookup = allVlookup + delimiter 
       End If 

       'append value to previous value 
       allVlookup = allVlookup + c.Offset(0, colIndex).Value 


       Set c = .FindNext(c) 
       'exit conditions 
       'no match found 
       If (c Is Nothing) Then 
        Exit Do 
        'we're back to start 
       ElseIf (c.Address = firstAddress) Then 
        Exit Do 
       End If 

      Loop 
     End If 
    End With 

End Function 

我茫然地解釋爲什麼發生這種情況。

我該怎麼做才能使輸出結果一致?

回答

2

它只給出第一場比賽的原因是因爲一個錯誤。請參閱底部的link(第5節)。

很久以前,我已經提交它作爲bug。如果你閱讀上面的鏈接,那麼我也提供了一個替代代碼。在情況下,鏈接永遠不會死的那個鏈接

提取物(它不應該)預期

.FindNext不以用戶定義函數的工作。你可以在正常的功能中使用它。

,假設我們已經在Sheet1這樣的數據:如果我們粘貼模塊在下面的代碼並運行它,然後我們會得到預期的結果作爲

A1 → Colt 
A2 → Holt 
A3 → Dolt 
A4 → Hello 

B1 → olt 

現在$A$1:$A$3

Sub Test() 
    Sample Sheets("Sheet1").Range("B1"), Sheets("Sheet1").Range("A1:A4") 
End Sub 

Sub Sample(FirstRange As Range, ListRange As Range) 
    Dim aCell As Range, bCell As Range, oRange As Range 
    Dim ExitLoop As Boolean 
    Set oRange = ListRange.Find(what:=FirstRange.Value, LookIn:=xlValues, _ 
    lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _ 
    MatchCase:=False, SearchFormat:=False) 
    ExitLoop = False 
    If Not oRange Is Nothing Then 
     Set bCell = oRange: Set aCell = oRange 

     Do While ExitLoop = False 
      Set oRange = ListRange.FindNext(After:=oRange) 

      If Not oRange Is Nothing Then 
       If oRange.Address = bCell.Address Then Exit Do 
       Set aCell = Union(aCell, oRange) 
      Else 
       ExitLoop = True 
      End If 
     Loop 
     MsgBox aCell.Address 
    Else 
     MsgBox "Not Found" 
    End If 
End Sub 

不過,如果你複製粘貼此功能預計它不會工作一個模塊中(在單元格C1說)=FindRange(A1,A1:A5)

代碼只會給你找到值的第一個實例從一個工作表中調用它而忽略其他

,因此結果,你會得到是$ A $ 2!

Function FindRange(FirstRange As Range, ListRange As Range) As String 
    Dim aCell As Range, bCell As Range, oRange As Range 
    Dim ExitLoop As Boolean 
    Set oRange = ListRange.Find(what:=FirstRange.Value, LookIn:=xlValues, _ 
    lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _ 
    MatchCase:=False, SearchFormat:=False) 
    ExitLoop = False 
    If Not oRange Is Nothing Then 
     Set bCell = oRange: Set aCell = oRange 

     Do While ExitLoop = False 
      Set oRange = ListRange.FindNext(After:=oRange) 

      If Not oRange Is Nothing Then 
       If oRange.Address = bCell.Address Then Exit Do 
       Set aCell = Union(aCell, oRange) 
      Else 
       ExitLoop = True 
      End If 
     Loop 
     FindRange = aCell.Address 
    Else 
     FindRange = "Not Found" 
    End If 
End Function 

我們需要從另一個角度來看待這個問題。

而不是使用.FindNext我們再次使用.Find直到我們得到所需的結果($ A $ 1:$ A $ 3)。請參閱下面哪些工作代碼:

Function FindRange(FirstRange As Range, ListRange As Range) As String 
    Dim aCell As Range, bCell As Range, oRange As Range 
    Dim ExitLoop As Boolean 
    Set oRange = ListRange.Find(what:=FirstRange.Value, LookIn:=xlValues, _ 
    lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _ 
    MatchCase:=False, SearchFormat:=False) 
    ExitLoop = False 
    If Not oRange Is Nothing Then 
     Set bCell = oRange: Set aCell = oRange 

     Do While ExitLoop = False 
      Set oRange = ListRange.Find(what:=FirstRange.Value, After:=oRange, LookIn:=xlValues, _ 
      lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _ 
      MatchCase:=False, SearchFormat:=False) 
      If Not oRange Is Nothing Then 
       If oRange.Address = bCell.Address Then Exit Do 
       Set aCell = Union(aCell, oRange) 
      Else 
       ExitLoop = True 
      End If 
     Loop 
     FindRange = aCell.Address 
    Else 
     FindRange = "Not Found" 
    End If 
End Function 
+0

我可以忍受這是一個錯誤。討厭,但是,很高興知道。 – enderland

2

請不要爲邏輯,但這裏是解決方案,它給了我相同的結果。更改.Find線分爲:

Set c = .Find(what:=lookupRange.Value2, after:=.Cells(1), LookIn:=xlValues, LookAt:=xlWhole) 

和另外改變.FindNext到:

Set c = .Find(what:=lookupRange.Value2, after:=c, LookIn:=xlValues, LookAt:=xlWhole) 

普萊斯也請記住,tableRange範圍應該有列標題。如果不是,結果順序將不會如預期的那樣一見鍾情。

附加(EDITED)最後一句的解釋。如果你有這種類型的表:range("A1:D3") ABC的

| A | B | C | D | 
    --+-----+-----+-----+-----+ 
    1 | ABC 1  2  A 
    2 | ABC 3  4  B 
    3 | ABC 5  6  C 

尋找擺脫列d,你會得到的結果數據時:BCD。要得到ABC,第一行應該有列標題。

+0

這似乎都很好 - 你有建議,如果'tableRange'沒有標題? – enderland

+0

另外,它是什麼使這項工作(和我的使用。找到不工作)?也許.FindNext不能從UDF調用 – enderland

相關問題