VBA динамически заполняет вложенную структуру данных - PullRequest
0 голосов
/ 01 марта 2020

У меня есть несколько SQL таблиц, некоторые из которых связаны, которые я хотел бы запросить один раз и сохранить локально в одной переменной. Я не могу предсказать длину данных заранее, поэтому мне нужна динамическая структура данных c.

Пример данных, которые я запрашиваю:

Таблица 1

NameA
Red
Green
Blue

Таблица 2

NameA   NameB
Red     A
Red     B
Red     C
Blue    D
Blue    E
Green   F

Таблица 3

NameA   NameC
Red     One
Blue    Two
Blue    Three
Blue    Four
Blue    Five
Green   Six
Green   Seven

Мне нужно иметь возможность фильтровать и получать доступ к NameB и Name C на основе значений NameA. Я бы предпочел вложенную структуру словаря, в которой я мог бы делать запрос, как показано ниже:

Table1("0") 'will equal "Red"
Table2("Red")("0") 'will equal "A"
Table2("Blue")("1") 'will equal "E"
Table3("Green")("1") 'will equal "Seven"
'note: point here is data structure, not order of results

Я пытался использовать вложенные словари VBA, но не смог обойти отсутствие функции «глубокого копирования». Один алгоритм, который я написал:

With SqlQueryResult
    i = 0
    Do Until .EOF
        Call Table1.Add(CStr(i), .Fields(0).Value)
        i = i + 1
        .MoveNext
    Loop
End With

For Each key In Table1.Keys
    SqlQueryResult = GetResultsFromQuery(SELECT NameB WHERE NameA = Table1(key))
    With SqlQueryResult
        i = 0
        Do Until .EOF
            Call TempDict.Add(CStr(i), .Fields(0).Value)
            i = i + 1
            .MoveNext
        Loop
    End With

    Set Table2(Table1(key)) = TempDict
    TempDict.RemoveAll
Next key

К сожалению, присвоение Dict другому Dict только устанавливает ссылку и фактически не копирует данные - когда я удаляю TempDict, вложенные данные из Table2 также удаляются.

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

Я смотрел на многомерные динамические массивы c - их нельзя назначить родительской структуре, такой как словарь. Я также не могу предсказать размер каждой из этих таблиц, например, Table1 может иметь размер 5/20/100 / et c, красный может иметь 2/5/100 / etcet c результаты в таблице 2, синий Результаты 1/20 / etcet c приведены в таблице 2. Redim работает только с одним измерением в массиве.

Я также кратко рассмотрел Коллекции, и я не уверен, что они жизнеспособны.

У меня нет большого опыта работы с классами, и я бы предпочел избегать очень сложного процесса - я хочу, чтобы было легко добавлять связанные и непривязанные (то есть данные, связанные с таблицей 1, такие как таблицы 2 и 3, против автономных данных, не связанных с какой-либо другой таблицей) этой программы, которые мне понадобятся в будущем. (Моим эталоном для "easy" является pandas фрейм данных в python).

1 Ответ

1 голос
/ 01 марта 2020

Простой класс-обертка для словарей сценариев, который реализует метод клонирования. Это должно хорошо работать с примитивными типами данных.

Option Explicit

Private Type State

    Dict                               As scripting.Dictionary

End Type



Private s                              As State

Private Sub Class_Initialize()

    Set s.Dict = New scripting.Dictionary

End Sub


Public Function Clone()

    Dim myClone As scripting.Dictionary
    Set myClone = New scripting.Dictionary

    Dim myKey As Variant
    For Each myKey In s.Dict

        myClone.Add myKey, s.Dict.Item(myKey)

    Next

    Set Clone = myClone

End Function


Public Property Get Item(ByVal Key As Variant) As Variant
    Item = s.Dict.Item(Key)
End Property

Public Property Set Item(ByVal Key As Variant, ByVal Value As Variant)
    s.Dict.Item(Key) = Value
End Property


Public Sub Add(ByVal Key As Variant, ByVal Item As Variant)
    s.Dict.Add Key, Item
End Sub

Теперь вы можете сказать

Set Table2.Item(Table1.Item(key)) = TempDict.Clone
...