#excel #vba
#excel #vba
Вопрос:
У меня есть лист со списком футбольных матчей и связанных данных. Каждую неделю я загружаю новые данные соответствия с веб-сайта, выбираю все новые соответствия и добавляю эти строки на лист, а затем копирую несколько формул из столбцов, которые есть только в моем листе и не являются частью загруженного листа.
Я создал приведенный ниже код для импорта данных, объединив сообщения отсюда и с других форумов:
Sub FD_new()
Dim rngLeague As Range
Dim cell As Range
Dim copiedRange As Range
Dim r As Integer
Dim LastRowSrc As Long
Dim LastRowDestA As Long
Dim DestWS As Worksheet
Dim DestWB As Workbook
Dim MaxDate As long
Set DestWB = Workbooks("Master Sheet")
Set DestWS = DestWB.Worksheets("Sheet1")
MaxDate = DateValue("03/03/2019")
'Build selected range to copy from dowload sheet
LastRowSrc = Cells(Rows.Count, "A").End(xlUp).Row
r = 0
Set rngLeague = Range("C2:C" amp; LastRowSrc)
For Each cell In rngLeague
If DateValue(cell) > MaxDate Then
If r = 0 Then
Set copiedRange = Range(cell.Offset(0, -2), cell.Offset(0, 11))
r = 1
Else
Set copiedRange = Union(copiedRange, Range(cell.Offset(0, -2), cell.Offset(0, 11)))
End If
End If
Next cell
'Copy and paste range once finished
If r = 1 Then
LastRowDestA = DestWS.Cells(Rows.Count, "A").End(xlUp).Row
copiedRange.Copy DestWS.Range("A" amp; LastRowDestA 1)
End If
End Sub
Однако сложность заключается в том, что в таблице загрузки иногда нет последних данных по всем лигам — некоторые обновляются ежедневно, некоторые — каждые 2-3 дня. Это означает, что в ручном режиме я должен проверить свой основной лист на наличие самой последней даты матча для каждой лиги, перейти к таблице загрузки, выбрать все матчи для этой лиги, которые после этой даты, и скопировать их. Следовательно, я не могу просто использовать один maxDate (как в приведенном выше коде).
Итак, я думаю, мне нужно обновить свой код, чтобы: — определить самую последнюю дату матча по лиге в главной таблице — определить все самые последние матчи для этой лиги в листе загрузки — скопировать их на главную таблицу — повторить для всех лиг
Конечно, может быть более простой способ сделать это!
Я думаю, мне нужно создать массив (или массивы) лиг и дат, но, если честно, я совершенно запутался.
Ответ №1:
Я предлагаю создать Dictionary
из ваших существующих данных, чтобы проверить, действительно ли сканируемые «новые» данные являются новыми или это повторение данных, которые у вас уже есть. Это нерабочий пример (потому что у меня нет столбцов вашей базы данных), но он иллюстрирует метод.
Сначала в меню VBE перейдите к Сервисам -> Ссылки… и добавьте библиотеку «Microsoft Scripting Runtime» в свой проект.
Затем создайте функцию, которая создаст Dictionary
из ваших существующих данных оценки. Это может выглядеть примерно так:
Function BuildDictionary() As Dictionary
Dim dbWS As Worksheet
Dim dbRange As Range
Dim dbArea As Variant
Set dbWS = ThisWorkbook.Sheets("MasterSheet")
Set dbRange = dbWS.Range("A1:Z20") 'this should be dynamically calc'ed
dbArea = dbRange 'copied to memory array
Dim dataDict As Dictionary
Set dataDict = New Dictionary
Dim i As Long
For i = LBound(dbArea, 1) To UBound(dbArea, 1)
Dim uniqueKey As String
'--- combine several fields to create a unique identifier for each
' game: Date League Teams
uniqueKey = dbArea(i, 1) amp; " " amp; dbArea(i, 2) amp; " " amp; dbArea(i, 3)
If Not dataDict.Exists(uniqueKey) Then
dataDict.Add uniqueKey, i 'stores the row number
End If
Next i
Set BuildDictionary = dataDict
End Function
Теперь в вашей основной логике вы возьмете этот созданный словарь и будете использовать его, чтобы проверить, существуют ли ваши новые данные уже в данных вашего основного листа:
Option Explicit
Sub ProcessNewData()
Dim existingData As Dictionary
Set existingData = BuildDictionary
'--- loop over your new data sheet and create a "key" from the
' new data fields
Dim newDataRange As Range
Dim newDataArea As Variant
Set newDataRange = ThisWorkbook.Sheets("NewDataSheet").Range("A1:Z20")
newDataArea = newDataRange
Dim i As Long
For i = LBound(newDataArea, 1) To UBound(newDataArea, 1)
Dim newKey As String
'--- build a key using the same fields in the same format
newKey = newDataArea(i, 1) amp; " " amp; newDataArea(i, 2) amp; " " amp; newDataArea(i, 3)
If Not existingData.Exists(newKey) Then
'--- add a new row of data to your master sheet data here and
' transfer from the newDataArea to the sheet
End If
Next dataRow
End Sub
Опять же, я не тестировал этот код, потому что у меня нет доступа к вашим форматам данных, но, надеюсь, это продвинет вас дальше по пути к рабочему решению.
Комментарии:
1. Большое вам спасибо! Я буду экспериментировать в выходные!
2. Хорошо, итак, я прошел через это и просто хочу повторить, как, по моему мнению, это работает. Мне нужно сохранить функцию в ее собственном модуле, и это создаст словарь для последующего использования. Я поместил Sub в свой собственный модуль, который выполняет перемещение данных. Затем у меня есть две таблицы: «MasterData» и «NewDataSheet». Моя задача — это то, что вы оставили мне для завершения 🙂 Полагаю, теперь, когда я знаю, что newKey не существует, мне нужно изолировать эту строку и создать диапазон объединения для копирования, как в моем исходном коде? Собираюсь попробовать и подумать о коде для этого…
3. Оба этих модуля могут использоваться в одном модуле. Фактически, они могут находиться в том же модуле, что и ваш собственный код. В модулях нет ничего волшебного, кроме как в качестве организующей вещи. Если вы размещаете вспомогательные модули / функции в отдельных модулях и вам нужно вызвать их из другого модуля, убедитесь, что они помечены как
Public
, иначе они могут бытьPrivate
. Смотрите это для справки.4. Черт возьми, я просто удивил себя! Удалось все выяснить! Огромное спасибо за вашу помощь!!
5. Привет, ребята. Не уверен, следует ли мне использовать новый поток, но у меня есть вопрос о построении на этом. Теперь, когда я создал свой обновленный «NewDataSheet», моя следующая задача — разложить данные по лигам в серию отдельных рабочих книг лиги в папке. Я нашел некоторый циклический код для этого, и я готов добавить в него приведенный выше подраздел, но проблема в том, что мне нужно создать новый словарь (через функцию) для каждого листа лиги, когда я перебираю их, а имя листа в функции статично — как мне привести подраздел и функцию в соответствие друг с другом?