Возникли проблемы с созданием пользовательской функции поиска в Excel. Проблема с совпадающими и конкатенированными диапазонами

У меня проблемы с моей большой таблицей. Я ввожу много необработанных данных в таблицу данных, а затем выполняю ряд поисков по данным. Используя встроенные функции, которые я придумал

=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 конкатенированными массивами, а затем использует точку в качестве индекса для значения, которое я хочу.

У меня их 8 (немного разных) в каждом ряду по 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

Это не работает! Он не только неправильно объединяется (каждый диапазон объединяется отдельно, а не объединяется строка за строкой), но и не любит какой-либо тип в одном из запросов. (отлаживать эти вещи непросто, поскольку функция фактически завершается (в ней нет никаких синтаксических ошибок), поэтому я не могу использовать встроенные пошаговые инструкции.

Любая помощь очень ценится.

Надеюсь, я дал достаточно подробностей, чтобы понять, что я пытаюсь сделать.

Ваше здоровье,

Стив

Match приведет к ошибке при использовании в VBA, если совпадения нет. Вы можете попробовать On Error Resume Next и проверить ошибку, или вы можете использовать метод Find объекта диапазона.

Fionnuala 11.01.2009 21:57
Преобразование HTML-таблицы в профессиональный документ Excel
Преобразование HTML-таблицы в профессиональный документ Excel
Это самый простой способ создания Excel из HTML-таблицы.
Импорт excel в laravel в базу данных
Импорт excel в laravel в базу данных
Здравствуйте, дорогой читатель, в этой статье я расскажу практическим и быстрым способом, как импортировать файл Excel в вашу базу данных с помощью...
2
1
1 496
3

Ответы 3

Как насчет:

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

Казалось бы, достигается то же, что и ваша функция Concat

Я не совсем уверен, как вы хотите, чтобы диапазоны были объединены, но я думаю, вам стоит взглянуть на Application.Union (Range, Range, ...) метод.

В примере из статьи:

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

См. Также Статья Тушара Мехты в Daily Dose of Excel, где он описывает следующий настраиваемый метод 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

Если вместо этого вы собираетесь использовать конкатенацию строк адресов диапазона, вам нужно добавить запятые, как показывает Барроус в своем сообщении. Например, Range("MyRange1, MyRange2") объединит два диапазона с именами «MyRange1» и «MyRange2», тогда как разделитель пробела без запятой, такой как Range("MyRange1 MyRange2"), вернет ПЕРЕСЕЧЕНИЕ (перекрытие) этих двух диапазонов.

Однако я бы рекомендовал избегать объединения строковых адресов и вместо этого использовать метод Application.Union(Range, Range).

Надеюсь это поможет...

Функцию ПОИСКПОЗ может быть сложно использовать в VBA, когда существует более одного критерия для сопоставления. То, что делается на листе - критерии соответствия, объединенные из разных ячеек с равным количеством связанных диапазонов, в обоих случаях с использованием оператора & - недостижимо в VBA, потому что оператор "&" VBA принимает только строки в качестве аргументов и потому что другие способы объединения диапазонов в VBA, функция Union и назначение с помощью нескольких аргументов адреса для Range, похоже, не создают массив, который будет работать с функцией сопоставления VBA.

Однако можно добиться того же эффекта, создав формулу рабочего листа, объединяющую ПОИСКПОЗ и сравнения массивов, а затем выполняя формулу с помощью функции VBA Evaluate. См. Мой ответ на этот ТАК вопрос, чтобы узнать, как работает этот подход.

Следующий код по существу повторно реализует исходную формулу рабочего листа, предоставленную Стивом, вне зависимости от ранее названных диапазонов на листе или значений критериев, указанных в коде (в отличие от конкретных ячеек на листе). Он написан как подпрограмма, но может быть легко преобразован в пользовательскую функцию.

  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

Другие вопросы по теме