在Excel中创建自定义查找功能时遇到问题。匹配和连接范围的问题

时间:2009-01-09 22:21:57

标签: excel vba function range concatenation

我在使用我的大型电子表格时遇到了一些麻烦。我将大量原始数据导入数据表,然后对数据进行大量查找。使用内置函数我想出了

=IF(ISNA(INDEX(Data!$L$7:$L$1100,MATCH(Data!$I$2&$B$199&$B29&Data!$J$5,Data!$K$7:$K$1100&Data!$J$7:$J$1100&Data!$I$7:$I$1100&Data!$N$7:$N$1100,0))),"0",INDEX(Data!$L$7:$L$1100,MATCH(Data!$I$2&$B$199&$B29&Data!$J$5,Data!$K$7:$K$1100&Data!$J$7:$J$1100&Data!$I$7:$I$1100&Data!$N$7:$N$1100,0)))

不漂亮!基本上,它使用4个变量进行两次相同的查找,并将它们与4个连接数组进行匹配,然后将该点用作我想要的值的索引。

我有4张(略有不同),每张4张,每张96张。编辑它们很痛苦!

由于本月数据集量大幅增长,外部频段(x1100)已经超越(经验教训,大型数据永远不够)。不幸的是,这个功能的限制不会让我使用L:L或类似的任何有用的东西。

我尝试将代码重写为用户定义的函数,我可以在其中输入4个变量,然后得到答案,但在组合数组时失败了。

我已经在原始函数名称中给出了上面列出的范围以使事情更容易(并且已经扩展它们以使用更宽范围的值),所以我可以重写所有函数以仅使用命名范围,但仍然如果我需要更改代码,我就会陷入困境。

这是我到目前为止所拥有的:

    Function Windows_Util(itma As String, env As String)

v = "Windows Server" & env & itma & ""
r = Concat(Range("Utilchassis"))
r = r & Concat(Range("Utilenv"))
r = r & Concat(Range("UtilITMA"))
r = r & Concat(Range("UtilOS"))

m = WorksheetFunction.Match(v, r, 0)

i = WorksheetFunction.Index(Range("Utilavg"), m)


If WorksheetFunction.IsNA(i) Then
    Windows_Util = 0
Else
    Windows_Util = i
End If

End Function


Function Concat(myRange As Range, Optional myDelimiter As String)

Dim r As Range

Application.Volatile

For Each r In myRange
   If Len(r.Text) Then
       Concat = Concat & IIf(Concat <> "", myDelimiter, "") & r.Text
   End If
Next

End Function

这不起作用!它不仅错误地连接(每个范围被单独连接,而不是逐行组合),它不喜欢其中一个查询中的某些类型。 (调试这些东西并不容易,因为函数实际完成(它没有任何语法错误),所以没有内置的步骤我可以使用。

非常感谢任何帮助。

希望我已经给出足够的细节来理解我正在尝试做的事情。

干杯,

史蒂夫

3 个答案:

答案 0 :(得分:1)

怎么样:

r = Range("Utilchassis,Utilenv,UtilITMA,UtilOS")

这似乎与你的Concat功能相同

答案 1 :(得分:1)

我不确定你想如何将Ranges整齐,但我认为你应该看一下Application.Union(Range, Range, ...) method

在文章的例子中:

Set bigRange = Application.Union(Range("Range1"), Range("Range2"))

另请参阅Article in the Daily Dose of Excel by Tushar Mehta,其中描述了以下自定义Union(Range,Range)方法,可以更好地处理'Nothing'(null)输入:

Function Union(Rng1 As Range, Rng2 As Range) As Range
    If Rng1 Is Nothing Then
        Set Union = Rng2
    ElseIf Rng2 Is Nothing Then
        Set Union = Rng1
    Else
        Set Union = Application.Union(Rng1, Rng2)
    End If
End Function

相反,如果你要使用范围地址的字符串连接,那么你必须添加逗号,正如Barrowc在他的帖子中显示的那样。例如Range("MyRange1, MyRange2")将联合名为“MyRange1”和“MyRange2”的两个范围,而没有逗号的空格分隔符(例如Range("MyRange1 MyRange2"))将返回这两个范围的INTERSECTION(重叠)。

但是,我建议避免串联地址并使用Application.Union(Range, Range)方法。

希望这会有所帮助......

答案 2 :(得分:0)

当有多个标准匹配时,MATCH函数在VBA中使用可能很棘手。在工作表中做了什么 - 匹配标准从不同的单元格连接到相同数量的连接范围,在两种情况下使用&amp;运算符 - 在VBA中无法实现,因为VBA“&amp;”运算符只接受字符串作为参数,并且因为在VBA中连接范围的其他方式,Union函数和通过Range的多个地址参数赋值,似乎不会生成一个可以与VBA匹配函数一起使用的数组。

但是,通过构建组合MATCH和数组比较的工作表公式,然后使用VBA评估函数执行公式,可以实现相同的效果。请参阅我对this SO question的回答,详细了解此方法的工作原理。

以下代码实质上重新实现了Steve提供的原始工作表公式,而不依赖于工作表中先前命名的范围或代码中指定的条件值(与工作表中的特定单元格相对)。它被写为sub,但可以很容易地转换为用户定义的函数。

  Sub x4match()

    Dim adr1 As String, adr2 As String, adr3 As String, adr4 As String
    Dim Rng1 As Range, Rng2 As Range, Rng3 As Range, Rng4 As Range
    Dim name1 As String, name2 As String, name3 As String, name4 As String
    Dim idx As Variant
    Dim resultRng As Range
    Dim result As Variant

    With ThisWorkbook.Worksheets("Data")

       adr1 = "I2"
       adr2 = "B199"
       adr3 = "B29"
       adr4 = "J5"

       Set Rng1 = .Range("K7:K1100")
       Set Rng2 = .Range("J7:J1100")
       Set Rng3 = .Range("I7:I1100")
       Set Rng4 = .Range("N7:N1100")
       Set resultRng = .Range("L7:L1100")

       .Names.Add Name:="name1", RefersTo:=Rng1
       .Names.Add Name:="name2", RefersTo:=Rng2
       .Names.Add Name:="name3", RefersTo:=Rng3
       .Names.Add Name:="name4", RefersTo:=Rng4

       idx = Evaluate("IFERROR( MATCH(1, --(" & adr1 & "=name1) * --(" & _
                     adr2 & "=name2) * --(" & adr3 & "=name3) * --(" & _ 
                     adr4 & "=name4), 0), 0)")

       If idx <> 0 Then
          result = .Cells(resultRng.Row + idx - 1, resultRng.Column).Value
       End If

      .Names("name1").Delete
      .Names("name2").Delete
      .Names("name3").Delete
      .Names("name4").Delete

    End With

  End Sub