Excel VBA — получение данных из сводной таблицы с использованием 3 элементов строки и 1 элемента столбца

#excel #vba #pivot-table

#преуспеть #vba #сводная таблица

Вопрос:

У меня есть сводная таблица с более чем 11 000 строками данных и 53 столбцами. Мне нужен фрагмент кода, который очень эффективно извлекает данные из определенной ячейки сводной таблицы.

Вот как выглядит сводная таблица: Сводная таблица

Мне нужно иметь возможность извлекать данные из определенных ячеек, используя три (3) столбца слева в качестве условий выбора правильной строки и смещения в правильный столбец, используя номера недель 1-50 вверху. Извлечение данных

Вот фрагмент моего текущего кода (который работает, но, вероятно, крайне неэффективен, поскольку мне нужно выполнить этот запрос примерно 48 раз прямо сейчас.

 Dim oWB As Workbook: Set oWB = Workbooks.Open(tWB.Path amp; "Telledata egeneide YTD.xlsx", ReadOnly:=True)
Dim oWS As Worksheet: Set oWS = oWB.Sheets("Telledata")
Dim pivotdata As Integer
Dim storeNo As Integer = 1101 'Example only - this can be anything between 1101 and 1199
Dim storeLoc As String = "0002" 'Example only - this value can be anything between 0001 and 0003
Dim materialGroup As Integer = 1120 'Example only - this can be anything between 1110 and 1899
Dim week as Integer = 11 'Example only - this can be anything between 1 and 50

pivotdata = Application.WorksheetFunction.CountIfs(oWS.Range("A:A"), storeNo, _
                                    oWS.Range("B:B"), storeLoc, _
                                    oWS.Range("C:C"), materialGroup, _
                                    oWS.Range("C:C").Offset(0, week), ">4")
 

Я ищу значения, превышающие 4. Как уже упоминалось, запрос в конце должен выполняться до 48 раз в том виде, в каком он есть в настоящее время, поскольку переменные в фрагменте кода изменяются.

Пример запроса:

 storeNo: 1101
storeLoc: 0001
materialGroup: 1141, 1142, 1143, 1410, 1420, 1451, 1220, 1260, 1270, 1710, 1720, 1730
week: 11, 12

storeNo: 1101
storeLoc: 0002
materialGroup: 1141, 1142, 1143, 1410, 1420, 1451, 1220, 1260, 1270, 1710, 1720, 1730
week: 11, 12
 

Как вы можете видеть, все запросы должны выполняться дважды (для каждого хранилища), плюс я должен проверить два столбца НЕДЕЛИ (выбранная неделя и неделя после).

Я думал о цикле для / для каждого цикла, но не уверен, как это сделать…

Комментарии:

1. Dim storeLoc As Integer = 0002 К вашему сведению 0002 , это не целое число — если оно имеет начальные нули, оно может быть только текстом / строкой. Как эти значения хранятся в базовых данных — в виде текста?

2. Кроме того, хорошая выноска на ведущих 0s @TimWilliams. OP — вам также нужно будет решить эту проблему в моем решении, если вы решите пойти по этому пути. Предполагая, что ваши сводные поля являются текстовыми, тогда ввод, который вы ищете, также должен быть текстовым (т. Е. 0002 <> 2 Насколько соответствует совпадению)

3. Да, это должна была быть строка, извините😉 Начальные нули должны быть там, но это не обязательно целое число. Просто перепутал при упрощении кода, который будет представлен здесь.

4. В будущем не добавляйте формулу в качестве тега, если вы не можете использовать решение формулы. Если вам нужен VBA, просто добавьте этот тег.

Ответ №1:

Вот один из подходов, использующих поиск по словарю на основе уникальных комбинаций 3 столбцов поиска:

(непроверенный)

 Sub Tester()
    
    Dim pt As PivotTable, rngRows As Range, rngData As Range
    Dim dict As Object, arrRows, arrData, r As Long, k
    
    Set pt = ActiveSheet.PivotTables(1)
    
    'https://peltiertech.com/referencing-pivot-table-ranges-in-vba/
    Set rngRows = pt.RowRange   'get the rows range (includes headers)
    Set rngRows = rngRows.Offset(1, 0).Resize(rngRows.Rows.Count - 1) 'exclude headers
    arrRows = rngRows.Value     '... get as 2D array
    
    'create lookup based on the 3 columns
    Set dict = CreateObject("scripting.dictionary")
    For r = 1 To UBound(arrRows, 1)
        k = Key(arrRows(r, 1), arrRows(r, 2), arrRows(r, 3))
        dict(k) = r 'link the key to the row number
    Next r
    
    Set rngData = pt.DataBodyRange    'the data from the table
    arrData = rngData.Value           '... as 2D array
    
    
    'now you can use the lookup to quickly locate the data you want
    k = Key(storeNo, storeLoc, materialGroup)
    If dict.exists(k) Then
        weekVal = arrData(dict(k), WeekNum)
        If weekNum < UBound(arrData, 2) Then 
            nextWeekVal = arrData(dict(k), WeekNum   1)
        End If
    Else
        'no match found
    End If
    
End Sub

'create key by concatenating the values with "|"
Function Key(v1, v2, v3)
    Key = Join(Array(v1, v2, v3), "|")
End Function

 

Комментарии:

1. Спасибо, это выглядит многообещающе из того, что я вижу! 😊 Я протестирую его как можно скорее.

2. k = Key(arrRows(r, 1), arrRows(r, 2), arrRows(r, 3)) выдает следующую ошибку: ошибка компиляции: суб или функция не определены

3. Вы скопировали Key функцию в нижней части кода?

4. Нет, это сработало! 🙂 Теперь работает как шарм, за исключением того, что он получает значение из строки ниже той, из которой он должен извлекаться. Поэтому, когда materialGroup = 1110, вместо этого будет выполняться поиск 1120 (строка ниже). Вероятно, просто одно число, которое необходимо изменить.

5. Хммм, похоже pt.RowRange , включает заголовки — внес изменения, чтобы учесть это…

Ответ №2:

Решение формулы

Вы можете использовать INDEX amp; MATCH здесь, чтобы извлечь значение, соответствующее строке, которая соответствует вашему storeNo, storeLoc, materialGroup, и столбцу, который соответствует вводу недели.

 =INDEX($A$1:$F$4,MATCH(1,($A$1:$A$4=H2)*($B$1:$B$4=I2)*($C$1:$C$4=J2),0),MATCH(K2,$A$1:$F$1))
 

Ссылка на таблицу

Предполагая структуру таблицы (или сводной таблицы), как показано ниже…

введите описание изображения здесь

И входная таблица с целевыми критериями, подобными этому…

введите описание изображения здесь

В зависимости от вашей версии Excel вам может потребоваться подтвердить эту формулу в виде массива. Для этого введите формулу и подтвердите с CTRL помощью SHIFT ENTER

Комментарии:

1. Очень интересное решение, спасибо, я рассмотрю это. 😊 Но это должно быть в виде кода VBA. Возможно, можно использовать EVALUATE для перевода этого в VBA (?)

2. errrrrr тогда почему вы пометили это формулой Excel…

3. Извините, возможно, это была не лучшая идея. Но, тем не менее, ваше решение интересно. Это может привести меня в правильном направлении. Спасибо за ваш вклад здесь. 😊

4. Не беспокойтесь — решение Tims будет быстрым. Намного быстрее, чем цикл. Вы можете воссоздать это в VBA, но вы также можете использовать инструменты, доступные в VBA (например, dictionary)