Страницы: 1
RSS
Сводная макросом (не объект). Как построить из плоской таблицы аналог сводной таблицы со смешанной иерархией, MacroPivot (not Excel object). Create analog of Pivot Table from Table by Macro. Mixed hierarchy
 
Приветствую!

Дано:
1. Пользователь строит "а-ля сводную" таблицу с иерархией (Лист 1)
    • максимум 6 уровней: Объект → Раздел → Подраздел → Группа → Заголовок → Работа
    • внутри Объекта (1ый уровень) структура не меняется
    • в таблице может быть несколько объектов
    • у разных объектов может быть разная структура
    • иерархия по всей таблице уникальна — так я контролирую однообразие структуры внутри Объекта
2. Эта "а-ля сводная" преобразовывается в плоскую Таблицу (Лист 2)

Вопрос:
как макросом сделать обратное 2ому действие — то есть как из плоской на Листе 2 получить сводную на Листе 1?
Скрины и Файл

PowerPivot не предлагать.
Желательно обойтись и без штатных сводных, но если с ними намного проще/быстрее, то можно.
"В лоб" я могу сделать, но хотелось бы что-то более-менее универсальное, что поддерживало бы N уровней. Это не обязательно - посмотрю код и сам подпилю.
Надеюсь, у кого-то есть наработки в этой области…
Изменено: Jack Famous - 28.07.2022 11:42:24
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
PowerPivot не предлагать.
А Power Query, мне кажется там будет проще. Сейчас подойдет кто-нибудь из знатоков и удивят  :D
Изменено: Msi2102 - 28.07.2022 12:35:50
 
Цитата
Msi2102: Power Query, мне кажется там будет проще
обновление запроса обычно занимает больше времени, чем обновление штатной сводной, не говоря уже про макросы.
Однако, это вариант я рассматриваю и жду предложений  :)

Макросом я заманался ломаную структуру восстанавливать - делаю вариант на предварительной подготовке данных (чтобы сортировка была корректной) с последующей агрегацией в штатной сводной.
Изменено: Jack Famous - 28.07.2022 12:48:40
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Jack Famous, Мне кажется, что формирование номера в плоской таблице не совсем корректное, если взять например Объект 3 в Вашей плоской таблице. Мне кажется, что если есть подраздел, то должен быть и раздел, то есть иерархия будет не 3.1.1.1, а 3.1.1.1.1, иначе смысл этой нумерации теряется
Изменено: Msi2102 - 28.07.2022 15:40:30
 
Цитата
Msi2102: если есть подраздел, то должен быть и раздел
вы либо мало дела имели с иерархиями в жизни, либо только с идеальными  :D
Если бы структура была одинаковая, то, конечно, проблемы бы не было и код был бы намного проще и легче, но в том-то и особенность, что уровни легко пропускаются, а пустые уровни никто делать не даст — отчёт из-за этого выглядит отвратительно…

Удалось добиться только однородности внутри объекта: то есть, если есть, например, Раздел, то внутри Объекта уже нельзя создать Подраздел/Группу/Заголовок без него. Если и это опустить, то вообще теряется однозначность, что и куда относится.

Вернулся к макросу. Выводить в скрытую таблицу, обновлять сводную и брать структуру из нёё — слишком расточительно по времени и некрасиво с точки зрения проекта.
Изменено: Jack Famous - 28.07.2022 15:49:21
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Сделал. Работает очень быстро. Объяснять полностью, к сожалению, долго, как и адаптировать рабочий макрос к примеру
Реальный код
Алгоритм кратко
Кому нужно будет подобное - обращайтесь. Будем пилить под задачу.
Изменено: Jack Famous - 28.07.2022 18:12:52
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Jack Famous, Вот ещё вариант. Только слино не ругайся, если, что-то лишнее осталось или недописал, спешил домой, но вроде работает, если конечно я тебя понял правильно. И ещё для простоты поменял местами в плоской таблице столбец Работа и Иерархия. А то нужно было бы ещё кодить, так проще, если понравится, то допишешь для своей таблицы. И для простоты перетащил все таблицы на один лист, но это для тебя не проблема  :D  :D  :D

Код
Sub Макрос3()
Dim arr2(0 To 5), arr3, n As Integer, m As Integer, i As Integer
arr = ActiveSheet.ListObjects("tblHier34").DataBodyRange
Set dic = CreateObject("Scripting.Dictionary")
For n = 1 To UBound(arr)
    arr1 = Split(arr(n, 7), ".")
    k = 0
    For m = 1 To 6
        If Not arr(n, m) = "—" Then
            arr2(m - 1) = arr1(k): k = k + 1: 'j = j + 1
        Else
            arr2(m - 1) = "—" ': j = j + 1
        End If
    Next m
    arr2(UBound(arr2)) = arr1(UBound(arr1))
    If Not dic.exists(arr2(0)) Then Set dic(arr2(0)) = CreateObject("Scripting.Dictionary"): If arr2(0) <> "—" Then i = i + 1
    If Not dic(arr2(0)).exists(arr2(1)) Then Set dic(arr2(0))(arr2(1)) = CreateObject("Scripting.Dictionary"): If arr2(1) <> "—" Then i = i + 1
    If Not dic(arr2(0))(arr2(1)).exists(arr2(2)) Then Set dic(arr2(0))(arr2(1))(arr2(2)) = CreateObject("Scripting.Dictionary"): If arr2(2) <> "—" Then i = i + 1
    If Not dic(arr2(0))(arr2(1))(arr2(2)).exists(arr2(3)) Then Set dic(arr2(0))(arr2(1))(arr2(2))(arr2(3)) = CreateObject("Scripting.Dictionary"): If arr2(3) <> "—" Then i = i + 1
    If Not dic(arr2(0))(arr2(1))(arr2(2))(arr2(3)).exists(arr2(4)) Then Set dic(arr2(0))(arr2(1))(arr2(2))(arr2(3))(arr2(4)) = CreateObject("Scripting.Dictionary"): If arr2(4) <> "—" Then i = i + 1
    If Not dic(arr2(0))(arr2(1))(arr2(2))(arr2(3))(arr2(4)).exists(arr2(5)) Then Set dic(arr2(0))(arr2(1))(arr2(2))(arr2(3))(arr2(4))(arr2(5)) = CreateObject("Scripting.Dictionary"): i = i + 1
Next n
ReDim arr3(1 To i, 1 To 11)
n = 0
m = 1
For Each y In dic
    n = n + 1
    arr3(n, 1) = y
    arr3(n, 2) = "—"
    arr3(n, 3) = "—"
    arr3(n, 4) = "—"
    arr3(n, 5) = "—"
    arr3(n, 6) = y
    arr3(n, 7) = "о"
    arr3(n, 8) = arr(m, 1)
    For Each y1 In dic(y)
        If y1 <> "—" Then
            n = n + 1
            arr3(n, 1) = y
            arr3(n, 2) = IIf(y1 = "—", "—", Replace(y & "." & y1, ".—", ""))
            arr3(n, 3) = "—"
            arr3(n, 4) = "—"
            arr3(n, 5) = "—"
            arr3(n, 6) = Replace(y & "." & y1, ".—", "")
            arr3(n, 7) = "р"
            arr3(n, 8) = arr(m, 2)
        End If
        For Each y2 In dic(y)(y1)
            If y2 <> "—" Then
                n = n + 1:
                arr3(n, 1) = y
                arr3(n, 2) = IIf(y1 = "—", "—", Replace(y & "." & y1, ".—", ""))
                arr3(n, 3) = IIf(y2 = "—", "—", Replace(y & "." & y1 & "." & y2, ".—", ""))
                arr3(n, 4) = "—"
                arr3(n, 5) = "—"
                arr3(n, 6) = Replace(y & "." & y1 & "." & y2, ".—", "")
                arr3(n, 7) = "п"
                arr3(n, 8) = arr(m, 3)
            End If
            For Each y3 In dic(y)(y1)(y2)
                If y3 <> "—" Then
                    n = n + 1
                    arr3(n, 1) = y
                    arr3(n, 2) = IIf(y1 = "—", "—", Replace(y & "." & y1, ".—", ""))
                    arr3(n, 3) = IIf(y2 = "—", "—", Replace(y & "." & y1 & "." & y2, ".—", ""))
                    arr3(n, 4) = IIf(y3 = "—", "—", Replace(y & "." & y1 & "." & y2 & "." & y3, ".—", ""))
                    arr3(n, 5) = "—"
                    arr3(n, 6) = Replace(y & "." & y1 & "." & y2 & "." & y3, ".—", "")
                    arr3(n, 7) = "г"
                    arr3(n, 8) = arr(m, 4)
                End If
                For Each y4 In dic(y)(y1)(y2)(y3)
                    If y4 <> "—" Then
                        n = n + 1:
                        arr3(n, 1) = y
                        arr3(n, 2) = IIf(y1 = "—", "—", Replace(y & "." & y1, ".—", ""))
                        arr3(n, 3) = IIf(y2 = "—", "—", Replace(y & "." & y1 & "." & y2, ".—", ""))
                        arr3(n, 4) = IIf(y3 = "—", "—", Replace(y & "." & y1 & "." & y2 & "." & y3, ".—", ""))
                        arr3(n, 5) = IIf(y4 = "—", "—", Replace(y & "." & y1 & "." & y2 & "." & y3 & "." & y4, ".—", ""))
                        arr3(n, 6) = Replace(y & "." & y1 & "." & y2 & "." & y3 & "." & y4, ".—", "")
                        arr3(n, 7) = "з"
                        arr3(n, 8) = arr(m, 5)
                    End If
                    For Each y5 In dic(y)(y1)(y2)(y3)(y4)
                        n = n + 1
                        arr3(n, 1) = y
                        arr3(n, 2) = IIf(y1 = "—", "—", Replace(y & "." & y1, ".—", ""))
                        arr3(n, 3) = IIf(y2 = "—", "—", Replace(y & "." & y1 & "." & y2, ".—", ""))
                        arr3(n, 4) = IIf(y3 = "—", "—", Replace(y & "." & y1 & "." & y2 & "." & y3, ".—", ""))
                        arr3(n, 5) = IIf(y4 = "—", "—", Replace(y & "." & y1 & "." & y2 & "." & y3 & "." & y4, ".—", ""))
                        arr3(n, 6) = Replace(y & "." & y1 & "." & y2 & "." & y3 & "." & y4 & "." & y5, ".—", "")
                        arr3(n, 8) = arr(m, 6)
                        arr3(n, 9) = arr(m, 8)
                        arr3(n, 10) = arr(m, 9)
                        arr3(n, 11) = arr(m, 10)
                        m = m + 1
                    Next
                Next
            Next
        Next
    Next
Next
Cells(2, 24).Resize(UBound(arr3), 11) = arr3
End Sub

PS: коротко об алгоритме, собрал всё в список списков, а потом развернул ;)
Изменено: Msi2102 - 28.07.2022 18:57:44
 
Msi2102, благодарю — лишним точно не будет  :idea:
Цитата
Msi2102: собрал всё в список списков, а потом развернул
полагаю, как-то так работает и штатная сводная  :)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Страницы: 1
Наверх