#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)