5

Excelから(セル内で)関数を呼び出すと:

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

対vba経由

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

異なる結果が得られます。Excel から呼び出された場合、最初の一致のみが取得されますが、同じパラメーター (Rangeサブを実行できるように引数に追加することを除く) を使用して vba テスト サブから呼び出すと、完全な結果 (複数) が取得されます。

私が使用している機能は次のとおりです。

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

なぜこれが起こっているのかを説明するのに途方に暮れています。

出力を同一にするにはどうすればよいですか?

4

2 に答える 2

3

.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範囲には列のタイトルが必要であることにも注意してください。そうでない場合、結果の順序は期待どおりになりません。

最後の文の追加(編集済み)説明。そのタイプのテーブルがある場合:

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

ABC を検索しrange("A1:D3")て列 D からデータを取得すると、次の結果が得られますBCD。取得するABCには、最初の行に列のタイトルが必要です。

于 2013-03-28T18:02:46.427 に答える
2

最初の一致のみが表示される理由は、バグのためです。下部にあるこのリンク(セクション 5) を参照してください。

私はずっと前にそれをバグとして提出しました。上記のリンクを読んだら、代替コードも提案しました。

リンクが切れた場合に備えて、そのリンクから抽出します (そうすべきではありません)。

.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 を使用する代わりに、目的の結果 ($A$1:$A$3) が得られるまで .Find を再度使用します。動作する以下のコードを参照してください。

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
于 2013-03-28T19:43:19.527 に答える