Необъяснимая ошибка несоответствия типов примерно каждые 10 000 итераций в Excel VBA - PullRequest
3 голосов
/ 13 марта 2011

У меня есть макрос VBA, который использует Microsoft MapPoint для вычисления расстояния между двумя местоположениями для каждой записи в моей электронной таблице.У меня есть около 120000 записей для обработки.Программа работает ровно около 10000 итераций, а затем возвращает ошибку несоответствия типов, где я определяю местоположения MapPoint в своем обработчике ошибок.В этот момент я выбираю «Отладка» и затем возобновляю выполнение без редактирования какого-либо кода, и он будет успешно запущен для еще примерно 10 000 записей, прежде чем произойдет то же самое.

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

Для справки:
- столбец M содержит местоположения формы "X County, ST"
- столбец AN содержит отдельное местоположение в виде ZIP
- столбецG содержит те же данные о местоположении, что и AN, но в форме "X County, ST"

Sub distance_from_res()
Dim oApp As MapPoint.Application
Dim k As Long  
Dim count As Long 
Dim errors As Long 

k = 0
count = Sheets("i1_20041").Range("A2", Sheets("i1_20041").Range("A2").End(xlDown)).count
errors = 0

  Set oApp = CreateObject("MapPoint.Application.NA.11")
  oApp.Visible = False
  Set objMap = oApp.NewMap
  Dim objRes As MapPoint.Location
  Dim objFish As MapPoint.Location

'Error executes code at 'LocError' and then returns to point of error.
  On Error GoTo LocError
  Do While k < count
    If Sheets("i1_20041").Range("M2").Offset(k, 0) <> "" Then
        'Sets MapPoint locations as [County],[State] from Excel sheet columns "INT_CNTY_ST" and "ZIP".
          Set objRes = objMap.FindResults(Sheets("i1_20041").Range("AN2").Offset(k, 0)).Item(1)
          Set objFish = objMap.FindResults(Sheets("i1_20041").Range("M2").Offset(k, 0)).Item(1)
        'Calculates distance between two locations and prints it in appropriate cell in Column AO.
          Sheets("i1_20041").Range("AO2").Offset(k, 0) = objRes.DistanceTo(objFish)
    Else
        errors = errors + 1
    End If
      k = k + 1
  Loop
 'Displays appropriate message at termination of program.
  If errors = 0 Then
    MsgBox ("All distance calculations were successful!")
  Else
    MsgBox ("Complete! Distance could not be calculated for " & errors & " of " & count & " records.")
  End If

Exit Sub

LocError:
    If Sheets("i1_20041").Range("G2").Offset(k, 0) = "" Then
        errors = errors + 1
    Else
        'THIS IS WHERE THE ERROR OCCURS!
          Set objRes = objMap.FindResults(Sheets("i1_20041").Range("G2").Offset(k, 0)).Item(1)
          Set objFish = objMap.FindResults(Sheets("i1_20041").Range("M2").Offset(k, 0)).Item(1)
        'Calculates distance between two locations and prints it in appropriate cell in Column AO.
          Sheets("i1_20041").Range("AO2").Offset(k, 0) = objRes.DistanceTo(objFish)
    End If
      k = k + 1
    Resume


End Sub

ОБНОВЛЕНИЕ: Я включил большинство предложений @winwaed и @Mike D, имой код стал более точным и не содержит ошибок.Однако старая проблема подняла голову в новой форме.Теперь, после примерно 10 000 итераций, код продолжается, но печатает расстояние ~ 10 000-й записи для каждой записи впоследствии.Я могу перезапустить код в проблемном месте, и он найдет расстояния, обычно для этих записей.Почему это случилось?Я разместил мой обновленный код ниже.

Sub distance_from_res()

Dim oApp As MapPoint.Application
Dim k As Long 
Dim rc As Long 
Dim errors As Long

Dim dist As Double
Dim zipRes As Range
Dim coRes As Range
Dim coInt As Range
Dim distR As Range

Set zipRes = Sheets("Sheet1").Range("C2")
Set coRes = Sheets("Sheet1").Range("B2")
Set coInt = Sheets("Sheet1").Range("E2")
Set distR = Sheets("Sheet1").Range("G2")

k = 0
rc = Sheets("Sheet1").Range("F2", Sheets("Sheet1").Range("F2").End(xlDown)).Count
errors = 0

'Start MapPoint application.
Set oApp = CreateObject("MapPoint.Application.NA.11")
oApp.Visible = False
Set objMap = oApp.NewMap
Dim objResultsRes As MapPoint.FindResults
Dim objResultsInt As MapPoint.FindResults
Dim objRes As MapPoint.Location
Dim objInt As MapPoint.Location

Do While k < rc
    'Check results for Res Zip Code.  If good, set first result to objRes.  If not, check results for Res County,ST.  If good, set first result to objRes.  Else, set objRes to Nothing.
    Set objResultsRes = objMap.FindResults(zipRes.Offset(k, 0))
    If objResultsRes.ResultsQuality = geoFirstResultGood Then
        Set objRes = objResultsRes.Item(1)
    Else
        Set objResultsRes = Nothing
        Set objResultsRes = objMap.FindResults(coRes.Offset(k, 0))
        If objResultsRes.ResultsQuality = geoFirstResultGood Then
            Set objRes = objResultsRes.Item(1)
        Else
            If objResultsRes.ResultsQuality = geoAmbiguousResults Then
                Set objRes = objResultsRes.Item(1)
            Else
                Set objRes = Nothing
            End If
        End If
    End If

    Set objResultsInt = objMap.FindResults(coInt.Offset(k, 0))
    If objResultsInt.ResultsQuality = geoFirstResultGood Then
        Set objInt = objResultsInt.Item(1)
    Else
        If objResultsInt.ResultsQuality = geoAmbiguousResults Then
            Set objInt = objResultsInt.Item(1)
        Else
            Set objInt = Nothing
        End If
    End If

    On Error GoTo ErrDist
    distR.Offset(k, 0) = objRes.DistanceTo(objInt)

    k = k + 1
Loop

Exit Sub


ErrDist:
    errors = errors + 1
    Resume Next

End Sub

Ответы [ 2 ]

3 голосов
/ 14 марта 2011

Вы строите несколько сложный объект диапазона (Range -> Offset -> Item).DIM объекты временного диапазона и делайте это поэтапно, чтобы вы могли увидеть, где именно проблема возникает

tmpR1 = Sheets("i1_20041").Range("G2")
tmpR2 = tmpR1.Offset(k,0)

, а затем проверьте свойство .Count .FindResult, прежде чем пытаться получить доступ к Item (1) .... может бытьэтот элемент не существует?!?

Debug.Print objMap.FindResult(tmpR2).Count

Подсказка: глядя на ваш код, я замечаю, что вы используете переменную "count".Это имя переменной перекрывается со свойством «Count» во второй строке кода, поэтому ключевое слово «Count» в конце оператора печатается строчными буквами.Это не имеет ничего общего с ошибками (мы притворяемся ;-)), но все равно плохой стиль.

1 голос
/ 14 марта 2011

MikeD прав с вашими опасными вызовами FindResults ().Тем не менее, есть лучший способ проверить результаты.«Коллекция FindResults» не является чистой коллекцией, но содержит дополнительные свойства, которые называются «ResultsQuality».Документы находятся здесь:

http://msdn.microsoft.com/en-us/library/aa493061.aspx

Resultsquality возвращает перечисление GeoFindResultsQuality.Вы хотите проверить значения geoAllResultsGood и geFirstResultGood.Все остальные результаты должны давать ошибку какого-либо результата.Обратите внимание, что ваш существующий код будет работать с (например) неоднозначными результатами поиска, даже если маловероятно, что первый результат будет правильным.Также он может совпадать с State или Zipcode (потому что это лучшее, что он может найти), что даст вам ошибочный результат.Используя ResultsQuality, вы можете обнаружить это.

Я бы все равно проверил значение Count как дополнительную проверку.

Обратите внимание, что ваш код вычисляет расстояния по прямой линии (большого круга).Таким узким местом будет геокодирование (FindResults).Если вы часто используете одни и те же места, механизм кэширования может значительно ускорить процесс.Если вы хотите рассчитать расстояние вождения, то на рынке есть ряд продуктов для этого (да, я написал два из них!).

...