2012-03-08 3 views
3

У меня есть скрипт vba, который должен копировать данные с одного листа на другой. Это происходит с помощью трех вложенных циклов. Выполнение кода при отладке кажется, что они работают отлично, но когда запускается скрипт vba, они, похоже, слишком рано останавливаются. В противном случае работает скрипт vba.Вложенные петли VBA, выходящие раньше

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

Лист организована следующим образом:

Лист1, содержит данные, которые должны быть скопированы.

  • Каждая строка содержит отдельный ответ, из которых имеются в тестовых данных
  • Лист содержит девять блоков данных 55, названный Эпизод 1-9. Каждый эпизод содержит столбец, где целое число представляет начало, конец и интервал времени.
  • В тестовых данных каждый эпизод идентичен, за исключением времени начала и окончания.
  • Максимальное значение для EndTime 36
  • тестовых данных в течение первых четырех Эпизод только блоков, так что Episode4 содержит EndTime = 36 для каждой строки

Sheet2, где данные должны идти - Первый столбец содержит каждый RespondentID, скопированный по 36 строкам. . Второй столбец содержит номера 1-36, представляя таким образом временной интервал для этого респондента. -11 Столбцы после этого содержат область, в которую помещаются данные, скопированные из листа 1 для этого респондента/времени. Эти 36x11 области названы «Response1-55» в тестовых данных

Логика сценария VBA выглядит следующим образом:

Счетчики: - п счетчик числа респондентов - г счетчик для числа эпизодов - i счетчик для строк в пределах копируемых ответов.

-> Для каждого ответа (начиная с п = 1 Респонденты)
-> Выберите первый эпизод (Начиная с R = 1 до 9)
---> Для каждого эпизода
--- > Прочтите начальные, конечные и временные интервалы
---> Начиная с i = Начать с i = Конец копировать соответствующие ячейки из n-й строки r-го эпизода
---> Скопировать эти ячейки в i-я строка текущего ответа на листе2
---> Когда вы достигнете EndTime текущего эпизода, перейдите к следующему (следующий r)
-> Если эпизод лет У только что закончил 36, как его EndTime, затем переходите к следующему ответу или продолжайте, пока не закончите эпизоды.
-> Следующий ответ

При отладке кода, похоже, делается именно это.

Однако, когда я запускаю скрипт vba на тестовом листе, он работает только для эпизодов 1 и 2. Данные из эпизодов 3 и 4 не копируются. На его месте ничего не копируется, и данные, которые копируются, являются правильными во всех отношениях. В любом случае сообщений об ошибках нет.

Если кто-нибудь может предположить, почему это может произойти, я бы построил для них настоящую церковь. Ответ также можно добавить здесь: https://stackoverflow.com/questions/119323/nested-for-loops-in-different-languages У которого еще нет раздела для VBA.

Ссылка на тест-лист здесь: http://dl.dropbox.com/u/41041934/MrExcelExample/TornHairExampleSheet.xlsm

Соответствующая часть кода здесь

Sub PopulateMedia() 
    Application.ScreenUpdating = False 

    'Count the total number of response rows in original sheet 
    Dim Responses As Long, n As Integer, i As Integer, r As Integer 
     Responses = (Sheets("Sheet1").UsedRange.Rows.Count - 3) ' equals 55 in test sheet 

    'For each response... 
    For n = 1 To Responses 
     i = 1 'Reset i for new response 
      Dim curr_resp As Range 
       Set curr_resp = Sheets(2).Range("Response" & n) 'Define a range containing all response data 

      For r = 1 To 9 'For each episode... 
       Dim curr_ep As Range 'Define a range containing episode data for all responses 
        Set curr_ep = Sheets(1).Range("episode" & r) 

       Dim Stime As Integer, Etime As Integer, Itime As Integer 'Variables contain start, end and inter-episode times 
        Stime = curr_ep.Cells(n, 1) 
        Etime = curr_ep.Cells(n, 17) 
        Itime = curr_ep.Cells(n, 19) 

        For i = Stime To (Etime + Itime) 'for each time-slot... 
         If i <= Etime Then 
          Dim a As Variant 
          a = curr_ep.Range(curr_ep.Cells(n - 3, 1), curr_ep.Cells(n - 3, 11)) 
          curr_resp.Rows(i) = a 'Copy data from above current episode to current response for slots between Stime and Etime 
         End If 
        Next i 
       If Etime = 36 Then Exit For 
      Next r 
    Next n 

    Application.ScreenUpdating = True 
End Sub 

Чтобы раскрыть, я уже была помощь по этому проекту с этого сайта, VBA copy from a union of two ranges to a row of another range но с тех пор код немного изменился, и это другая проблема.

Еще раз спасибо огромное за любую помощь, которая может возникнуть из-за этого. Я смотрел на это часами и не вижу, где ошибка. Любое руководство вообще очень ценилось.

+1

Вы можете пересмотреть всю конструкцию таблицы на каком-то этапе - используя именованные диапазоны, как вы делаете это к ошибкам и трудно отлаживать (как вы заметили). Excel большой и простой в использовании с табличными данными - вместо 9 отдельных диапазонов вы можете иметь один блок с дополнительным столбцом, содержащим номер эпизода, например. Это простое изменение значительно улучшит читаемость и код. – assylias

+0

Спасибо за обратную связь еще раз. Лист фактически создается программой, поэтому некоторые из беспорядков, но я понимаю, что вы имеете в виду, чтобы компенсировать выбор, а не использовать диапазоны. Текущий метод настолько близок, но если я не могу заставить его работать полностью, я буду использовать предложенный подход. В этом случае я буду просить вас ответить на этот вопрос, чтобы я мог принять его. Еще раз спасибо за это. Очень признателен. – TornHair

ответ

5

Я бы разместил это как комментарий, если бы мог, но это слишком долго. Так вот оно в качестве потенциального решения запроса/

Я думаю, что ваши ссылки диапазонвыхода вопрос

Приведенный ниже код представляет собой урезанную версию кода

curr_ep именованный диапазон эпизод1. Он имеет диапазон адреса $Y$4:$AQ$58

Когда петля через a вариант вы устанавливаете диапазон с этим синтаксисом
a = curr_ep.Range(curr_ep.Cells(n - 3, 1), curr_ep.Cells(n - 3, 11))
что эквивалентно a = curr_ep.Range("Y2:AQ2")

, который означает, что вы на самом деле, глядя на AW2:BG2 не Y2:AQ2, что я думаю, что вы, возможно, планировали, то есть вы строите непреднамеренное смещение

Sub PopulateMedia() 
    n = 1 
    r = 1 
    Dim curr_ep As Range 
    Dim curr_test As Range 
    Set curr_ep = Sheets(1).Range("episode" & r) 
    Set curr_test = curr_ep.Range(curr_ep.Cells(n - 3, 1), curr_ep.Cells(n - 3, 11)) 
End Sub 

enter image description here

+1

Если вы не знаете, как циклически перебирать код по очереди, например. получите желтый бар выше, вы должны следовать рекомендациям здесь по анализу макросов (http://www.excel4business.com/videos/analyzing-macros-error-handling.php). В принципе, если вы вводите точку разрыва, например. «Далее n», тогда вы можете оценить различные переменные/компоненты, когда код выходит из цикла r –

+0

Благодарим за комментарий. Я сделал такой код, но не знал, как проверить адрес переменных диапазона, как показывает вышеприведенный ответ.Я думаю, что вышеупомянутый ответ взломал его: счетчики циклов работают правильно, как показал отладочный файл, но копируют из неправильного эпизода. Спасибо за ссылку, я это рассмотрю сейчас. – TornHair

+0

Большое спасибо, я проверил оригинал, сделав диапазон и наблюдая его адрес при отладке, как показано, а смещение - это именно то, что происходит. Я думал, что линия, устанавливающая curr_test в вашем примере, будет выбирать от 1-го по 11-й столбцы от (три строки вверх от ...) n-й строки текущего эпизода. Теперь, когда проблема ясна, я буду искать то, что вводит это смещение. Большое вам спасибо за помощь и @assylias за альтернативное решение. – TornHair

Смежные вопросы