Вы предоставили много подробностей, но все еще довольно сложно понять, что происходит, не видя некоторого кода.В вашем вопросе я могу выделить как минимум 4 большие темы, которые вы переплетаете: производство, доступ к данным, VBA и лучшие практики кодирования.Мне трудно точно сказать, что вы спрашиваете, потому что объем ваших вопросов огромен.В любом случае, я ценю ваши попытки написать лучший код на VBA.
Мне сложно понять, что именно вы планируете делать с массивами.Вы говорите:
Недостатком является то, что я использую большую часть одной и той же базовой информации в нескольких процедурах, что требует от меня загрузки ее в массивы с небольшими отличиями несколько раз.
Я не уверен, что вы имеете в виду здесь.Используете ли вы массивы для представления строки данных, которые вы извлекли из базы данных?Если это так, вы можете рассмотреть возможность использования модулей класса вместо обычных «макро» модулей.Это позволит вам работать с полноценными объектами вместо массивов значений (или ссылок, в зависимости от обстоятельств).Классы требуют больше работы для установки и использования, но они значительно упрощают работу с вашим кодом и значительно помогут вам сегментировать ваш код.
Как уже указывал пользователь Emtucifor, могут существовать такие объекты, какADO Recordset
объекты (которые могут требовать установки Access ... не уверен), которые могут сильно помочь.Или вы можете создать свой собственный.
Вот длинный пример того, как использование класса может вам помочь.Хотя этот пример очень длинный, он покажет вам, как несколько принципов объектно-ориентированного программирования действительно могут помочь вам очистить ваш код.
В редакторе VBA перейдите на Insert > Class Module
.В окне «Свойства» (по умолчанию в левом нижнем углу экрана) измените имя модуля на WorkLogItem
.Добавьте следующий код в класс:
Option Explicit
Private pTaskID As Long
Private pPersonName As String
Private pHoursWorked As Double
Public Property Get TaskID() As Long
TaskID = pTaskID
End Property
Public Property Let TaskID(lTaskID As Long)
pTaskID = lTaskID
End Property
Public Property Get PersonName() As String
PersonName = pPersonName
End Property
Public Property Let PersonName(lPersonName As String)
pPersonName = lPersonName
End Property
Public Property Get HoursWorked() As Double
HoursWorked = pHoursWorked
End Property
Public Property Let HoursWorked(lHoursWorked As Double)
pHoursWorked = lHoursWorked
End Property
Приведенный выше код даст нам строго типизированный объект, специфичный для данных, с которыми мы работаем.Когда вы используете многомерные массивы для хранения ваших данных, ваш код выглядит следующим образом: arr(1,1)
- это идентификатор, arr(1,2)
- это PersonName, а arr(1,3)
- это HoursWorked.Используя этот синтаксис, трудно понять, что к чему.Предположим, вы по-прежнему загружаете свои объекты в массив, но вместо этого используете WorkLogItem
, который мы создали выше.Это имя, вы могли бы сделать arr(1).PersonName
, чтобы получить имя человека.Это делает ваш код намного проще для чтения.
Давайте продолжим двигаться с этим примером.Вместо хранения объектов в массиве, мы попробуем использовать collection
.
Далее, добавьте новый модуль класса и назовите его ProcessWorkLog
.Поместите туда следующий код:
Option Explicit
Private pWorkLogItems As Collection
Public Property Get WorkLogItems() As Collection
Set WorkLogItems = pWorkLogItems
End Property
Public Property Set WorkLogItems(lWorkLogItem As Collection)
Set pWorkLogItems = lWorkLogItem
End Property
Function GetHoursWorked(strPersonName As String) As Double
On Error GoTo Handle_Errors
Dim wli As WorkLogItem
Dim doubleTotal As Double
doubleTotal = 0
For Each wli In WorkLogItems
If strPersonName = wli.PersonName Then
doubleTotal = doubleTotal + wli.HoursWorked
End If
Next wli
Exit_Here:
GetHoursWorked = doubleTotal
Exit Function
Handle_Errors:
'You will probably want to catch the error that will '
'occur if WorkLogItems has not been set '
Resume Exit_Here
End Function
Приведенный выше класс будет использоваться для того, чтобы "что-то сделать" с коллекцией WorkLogItem
.Первоначально мы просто настроили его для подсчета общего количества отработанных часов.Давайте проверим код, который мы написали.Создайте новый модуль (на этот раз не модуль класса; просто «обычный» модуль).Вставьте следующий код в модуль:
Option Explicit
Function PopulateArray() As Collection
Dim clnWlis As Collection
Dim wli As WorkLogItem
'Put some data in the collection'
Set clnWlis = New Collection
Set wli = New WorkLogItem
wli.TaskID = 1
wli.PersonName = "Fred"
wli.HoursWorked = 4.5
clnWlis.Add wli
Set wli = New WorkLogItem
wli.TaskID = 2
wli.PersonName = "Sally"
wli.HoursWorked = 3
clnWlis.Add wli
Set wli = New WorkLogItem
wli.TaskID = 3
wli.PersonName = "Fred"
wli.HoursWorked = 2.5
clnWlis.Add wli
Set PopulateArray = clnWlis
End Function
Sub TestGetHoursWorked()
Dim pwl As ProcessWorkLog
Dim arrWli() As WorkLogItem
Set pwl = New ProcessWorkLog
Set pwl.WorkLogItems = PopulateArray()
Debug.Print pwl.GetHoursWorked("Fred")
End Sub
В приведенном выше коде PopulateArray()
просто создает коллекцию WorkLogItem
.В своем реальном коде вы можете создать класс для анализа ваших листов Excel или объектов данных для заполнения коллекции или массива.
Код TestGetHoursWorked()
просто демонстрирует, как использовались классы.Вы замечаете, что ProcessWorkLog
создается как объект.После создания экземпляра коллекция WorkLogItem
становится частью объекта pwl
.Вы замечаете это в строке Set pwl.WorkLogItems = PopulateArray()
.Затем мы просто вызываем написанную нами функцию, которая действует на коллекцию WorkLogItems
.
Почему это полезно?
Предположим, что ваши данные изменились, и вы хотите добавить новый метод.Предположим, что ваш WorkLogItem
теперь включает поле для HoursOnBreak
, и вы хотите добавить новый метод для его вычисления.
Все, что вам нужно сделать, это добавить свойство к WorkLogItem
, например, так:
Private pHoursOnBreak As Double
Public Property Get HoursOnBreak() As Double
HoursOnBreak = pHoursOnBreak
End Property
Public Property Let HoursOnBreak(lHoursOnBreak As Double)
pHoursOnBreak = lHoursOnBreak
End Property
Конечно, вам нужно будет изменить свой метод для заполнения вашей коллекции (пример метода, который я использовал, был PopulateArray()
, но вы, вероятно, должны иметь отдельный класс только для этого). Затем вы просто добавляете новый метод в класс ProcessWorkLog
:
Function GetHoursOnBreak(strPersonName As String) As Double
'Code to get hours on break
End Function
Теперь, если мы хотим обновить наш метод TestGetHoursWorked()
, чтобы он возвращал результат GetHoursOnBreak
, все, что нам нужно сделать, это добавить следующую строку:
Debug.Print pwl.GetHoursOnBreak("Fred")
Если вы передадите массив значений, представляющих ваши данные, вам нужно будет найти каждое место в вашем коде, где вы использовали массивы, а затем соответствующим образом обновить его. Если вместо этого вы используете классы (и их экземпляры), вы можете намного проще обновить свой код для работы с изменениями. Кроме того, когда вы разрешаете использование класса несколькими способами (возможно, одной функции требуется только 4 из свойств объектов, а другой функции потребуется 6), они все равно могут ссылаться на один и тот же объект. Это предотвращает использование нескольких массивов для различных типов функций.
Для дальнейшего прочтения я бы настоятельно рекомендовал бы получить копию Справочник разработчика VBA, 2-е издание . Книга полна замечательных примеров и лучших практик, а также множества примеров кода. Если вы вкладываете много времени в VBA для серьезного проекта, стоит потратить время на изучение этой книги.