Вот, нарвался на глюк. Может кому поможет. Беглый поиск по форуму явных аналогов не выявил, но если не так - не судите строго.
Ситуация достаточно типичная - после формирования силами VBA сводной таблицы и вставки на ее же место ее же значений возникает потребность заполнить пустоты полей области строк. Это делается заполнением всех пустот формулой, которую я называю "см.выше" (т.е. значение поля надо продублировать вниз на все строки этого поля - пока не встретится новое значение по данному полю). Это приводит наполнение сводной таблицы в нормализованный вид, пригодный для разного рода отчетов, ожидающих в каждой строке зоны данных увидеть заполненные данные в каждом столбце.
В общем вместо:
Код
Отдел А Иванов
Петров
Сидоров
Отдел Б
Власов
Тарасов
Кузьмин
Получаем:
Отдел А Иванов
Отдел А Петров
Отдел А Сидоров
Отдел Б Власов
Отдел Б Тарасов
Отдел Б Кузьмин
Код одолжен из книги, поэтому я был в нем уверен на все 100%:
Код
FinalReportRow = WSD.Range("R1048576").End(xlUp).Row
With Range("O2").Resize(FinalReportRow - 1, 1)
With .SpecialCells(xlCellTypeBlanks)
.FormulaR1C1 = "=R[-1]C"
End With
.Value = .Value
End With
Всё бы хорошо, но при загрузке большого объема данных формула глючит и заполняет не только пустоты, но и все ячейки данного столбца. В итоге он полностью заполняется самым верхним значением (или даже пустотой).
Глюк имел плавающий характер - данных 400 тысяч строк, импортированных из текстового файла, что и усиливало желание найти "левый символ" . В итоге методом половинного деления за 2,5 часа я его вычислил с точность до 10 строк. А потом - хвать, а демонов то и нет. Заполнение этих строк любыми другими (даже из уже прошедших проверку частей) также приводит к сбою. Потом я воспользовался гулглом, и нашел описание данного глюка. http://support.microsoft.com/kb/832293/ru
Вывод - гугл круче клоуна с половинным делением , поэтому если ошибка не лечится за 20 минут - разумно потратить 2 минуты на погуглить. Ты понял, Леша? (это я себе )
ЗЫ. Больше всего понравился статус глюка в базе данных Microsoft - прям вспоминается программистская байка - "если в вашей программе обнаружили глюк, не спешите его исправлять - позиционируйте его как уникальную особенность вашего программного продукта"
Excel поддерживает только до 8192 несмежных ячеек через макросы VBA.
На самом деле не ячеек, а областей. Этот факт неоднократно обсуждался на форуме. Лечится циклом, порциями. Или предварительной сортировкой, что для Alex-M не подходит.
А вообще, проблему можно было решить гораздо проще
Достаточно считать Range("O2").Resize(FinalReportRow - 1, 1) в массив, пробежаться по нему в цикле, простейшей проверкой заполнив пустые позиции значениями «сверху» И потом выгрузить массив на лист Всего-то 5 строк кода...
А использовать SpecialCells при количестве строк более 20 тыс, - это уже рискованное занятие. Цикл - почти всегда и быстрее, и проще.
Я так и сделал - через цикл. Правда, сразу же после чтения и записывал "если ты пустая, получи значение из Темр, а если нет - пропишись в Темр". И так сверху вниз в 1 проход. В целом меня скорость устроила. Но, признаться, не совсем догоняю в чем в данном случае выгода от массива - я ведь в нем ничего такого не обрабатываю и не вычисляю, а считать в каждую ячейку и записать в нее мне при любом раскладе придется.
Впрочем, я изучаю VBA только первые дни и откровенно говоря просто "не умею готовить" массивы - у меня счет идет на часы, поэтому я этот раздел в книге и на "практических тестах" особо детально не изучал, а тут, блин, еще эта сводная таблица чей-то на больших данных подвисает. Буду надеяться, что дело не в ней (вручную вроде делается), а в моем коде. Сейчас буду искать.
Но, признаться, не совсем догоняю в чем в данном случае выгода от массива
В любом случае будет быстрей, чем порциями SpecialCells. У меня 418248 строк обработал за 1.6 сек. Это никак не часы. Код такой:
Код
Public Sub www()
Dim a, i&, tmp, t!
t = Timer
a = ActiveSheet.UsedRange.Columns(1).Value
For i = 1 To UBound(a)
If a(i, 1) <> "" Then
tmp = a(i, 1)
Else
a(i, 1) = tmp
End If
Next
[a1].Resize(i - 1) = a
MsgBox Timer - t
End Sub
операции с ячейками листа из VBA - очень долгая штука. а у Вас их выполняется для каждой ячейки - по три. сравните с кодом KuklP - всего два обращения (записать в массив значения и выгрузить значения на лист) часы превратились в секунды.
фрилансер Excel, VBA - контакты в профиле "Совершенствоваться не обязательно. Выживание — дело добровольное." Э.Деминг
ikki, я мельком их посмотрел, но эксперименты пока не делал. Просто действительно времени в обрез. Уже завтра, в край вторник, мне нужен работающий код. Поэтому дело не в сложно-просто, а в ресурсе времени. Я не говорил и не говорю, что масивы это плохо. Видел, что они действительно в сотни раз ускоряют работу. Я лишь именно в моем случае так и не увидел выгоды, т.к. считал, что у меня тоже всего "2 касания". Если я чего-то не учитываю, подправьте пожалуйста. Вот мой код (заранее согласен что он не оптимален с каких-то других точек зрения, т.к. написал наспех).
Код
For i = 1 To finish - Range(start).Row
If Range(start).Offset(i, 0).Value = nosing Then
Range(start).Offset(i, 0).Value = temp
Else
temp = Range(start).Offset(i, 0).Value
End If
Next i
В принципе, наверное, temp = Range(start).Offset(i, 0).Value можно было заменить на temp = temp1, в которую изначально записывать Range(start).Offset(i, 0).Value.
У Вас два "касания" к каждой ячейке (или может даже три - не знаю, для определения значения по сдвигу нужно ли "касаться" исходной ячейки...) Умножьте количество строк на 2 - получите число "касаний". Если использовать массив - будет всего 2 "касания", вся остальная работа в памяти с данными, не касаясь таблицы/ячеек.
Hugo, т.е. считывание всей колонки и считывание 1 ячейки - одинаковы по времени? Если так, то я понял, почему так долго упрямился - для меня время считывания диапазона всегда подразумевало сложение времени считывания каждой ячейки. И только сейчас я начинаю "подозревавать", что не учитываю некую инициализирующую составляющую для каждого обращения к листу.
ЗЫ. "Я все ловлю на лету, но теперь то мне ясно, что конкретно вы имели в виду" (с) из пародии на одну песню.
Вот еще почему желательно использовать option explicit Еще дополню Игоря - запись в ячейку происходит гораздо медленнее, чем считывание из нее, поэтому в Вашем случае основное время(и весьма немалое) придется именно на запись в ячейки в цикле.
да, да, я что-то такое читал, и даже был душой "за", в смысле для себя решил "завтра обязательно поставлю". И признаться, когда писал nosing, внутренний голос что-то такое пытался мне донести, но было полчетвертого утра и мы оба хотели спать, поэтому диалог не состоялся.
Вставлю прямо сейчас. Если из-за этого я убил пару часов, то я убьюсь об стенку. Чувствую, на мне можно будет писать книжку "как я освоил VBA за Х дней и Y ляпов, про которые 120 раз написано на форуме"
Как однажды в сердцах воскликнул один "приверженец" тайм-менеджмента: "у меня нет времени, чтобы изучить как экономить время". Похоже это мой случай .
option explicit заставит Вас объявлять все переменные - таких необъявленных скорее всего наберётся много, если код большой. Но всё равно быстрее их все объявить, чем через неделю обнаружить, что что-то считается неправильно потому, что где-то переменная с, а где-то c Т.е. это ещё нужно суметь найти...
Hugo, а Вы не знаете обратного инструмента - т.е. нет ли каких-нибудь обработок, которые бы показывали в коде излишне объявленные переменные, рисовали бы графически структуру и т.п. "примочек" для удобства. Просто интересно - так как я подозреваю, что может быть я со злости за неделю я и рожу то, что наш отдел программирования не мог родить несколько лет, но как бывший программист я понимаю, какие у меня будут потом "ломки", когда я через 2 недели захочу разобраться в собственном коде. Поэтому хотелось бы все более-менее вылизать и откомментировать, чтобы потом легче жить.
От лишних объявленных переменных большого вреда не будет, а комментарии добавлять Вам никто не запретит. Еще - объявляйте переменные в столбик(а не в строку, как я) и тогда закомментировав по очереди, узнаете, какие лишние. Когда-то для ВБ существовала программа codecleaner. Аналогов для ВБА я не видел.
Володь, сейчас попробовал. Влепил в макрос из персонал пару левых переменных. Запустил кляйнер. Че-то он там чистил - не знаю. Отрапортовал, что все ОК. Переменные остались:( Мож я че не так делаю...