PasteSpecial дважды аварийно завершает работу Excel VBA

#excel #vba #crash #copy #copy-paste

Вопрос:

Я несколько раз искал решение для использования .PasteSpecial в макросе excel vba. У меня есть отчеты, которые иногда могут содержать тысячи строк. В этих отчетах два столбца, мне нужно объединить эти столбцы, чтобы, если в одном столбце есть пробелы, я хотел бы получить значение из второго столбца; в противном случае просто сохраните значение в первом столбце. Мне нужно применить это дважды в двух разных местах. Все это вложено в более крупный код.

Мое решение-использовать .PasteSpecial с «Пропуском заготовок». Это быстро обрабатывается Excel, намного быстрее, чем циклическое выполнение строки за строкой. Проблема в том, что код продолжает выводить excel из строя.

После отладки вот что я узнал до сих пор: *Первый .PasteSpecial всегда работает, но когда дело доходит до второго .По-особому это всегда терпит неудачу. *Я попробовал ОСТАНОВИТЬСЯ после первого .PasteSpecial, затем пройти через код, а затем пройти через второй.Специальный код работает просто отлично. *Если я пройду через второй .В прошлом это работает так, как будто ничего не случилось, но если я просто запущу код как обычно, он выйдет из строя. *Я поменял порядок двух .PasteSpecials в коде. Когда я это делаю, он больше не падает на проблемном .Специальная паста, но она выходит из строя на первоначально работающем .специальная паста.

Исходя из этого, я знаю, что проблема в том, что Excel это не нравится .Специальная вставка дважды в коде. Все еще не могу найти обходной путь. Я попытался очистить доску для клипов, и я недостаточно знаю, как настроить массив, не говоря уже о том, эффективно ли это для такого количества данных. Кто — нибудь знает решение или обходной путь?

Вот мой .специальный код.:

 MainSheet.Range("N:N").Copy
MainSheet.Range("P:P").PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:=True, Transpose:=False

MainSheet.Range("R:R").Copy
MainSheet.Range("Q:Q").PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:=True, Transpose:=False
 

Комментарии:

1. Что произойдет, если вы попытаетесь скопировать / вставить специальное вручную?

2. Вы пробовали Application.CutCopyMode=False переключаться между двумя операциями копирования/вставки?

3. Вам тоже нужно скопировать формат?

4. Если я попытаюсь сделать это вручную, это сработает просто отлично. Я попробовал приложение. CutCopyMode=False, и он все равно вылетает. Мне тоже не нужно форматирование.

Ответ №1:

Ваша проблема в том, что вы выделяете процессор для выполнения задач на уровне ОС, когда на самом деле вам ничего не нужно вставлять.

В ячейках есть значения… так сделай их равными и они… будет… быть…

 Range("C1").Value = Range("A1").Value
 

В качестве альтернативы вы можете использовать запрос мощности, чтобы просто сделать это, где таблица 2 Col2 равна нулю, а ID = ID

Комментарии:

1. Привет, спасибо за ответ, но это не соответствует моей цели. Чтобы уточнить мою цель: причина, по которой я использую .PasteSpecial, состоит в том, чтобы «Пропустить пробелы», чтобы, если в первом столбце есть пробелы, а во втором столбце (в той же строке) есть текст, он НЕ стирал текст второго столбца. Однако, если в обоих есть текст, текст первого столбца переопределяет текст второго столбца.

Ответ №2:

Не нуждаясь в формате, пожалуйста, протестируйте следующий код. Он использует массив, а не буфер обмена и работает быстрее. Если нет необходимости в существовании соответствия между строками в двух заполненных столбцах, вы можете воспользоваться следующим быстрым способом:

 Sub copyColumnsArray()
 Dim lastR As Long, arrCopy, arrFin, i As Long, k As Long
 
 lastR = MainSheet.Range("N" amp; rows.count).End(xlUp).row
 arr = MainSheet.Range("N1:N" amp; lastR).value
 
 'fill another array only with non empty values:__________________
 ReDim arrFin(UBound(arr) To 1): k = 1
 For i = 1 To UBound(arrCopy)
    If arrCopy(i, 1) <> "" Then arrFin(k, 1) = arrCopy(i, 1): k = k   1
 Next i
 ReDim Preserve arrFin(k - 1 To 1)
 '______________________________________________________
 
 MainSheet.Range("P1").Resize(UBound(arrFin), 1).value = arrFin
 
 lastR = MainSheet.Range("R" amp; rows.count).End(xlUp).row
 arr = MainSheet.Range("R1:R" amp; lastR).value
 
 'fill another array only with non empty values:__________________
 ReDim arrFin(UBound(arr) To 1): k = 1
 For i = 1 To UBound(arrCopy)
    If arrCopy(i, 1) <> "" Then arrFin(k, 1) = arrCopy(i, 1): k = k   1
 Next i
 ReDim Preserve arrFin(k - 1 To 1)
 '______________________________________________________
 
 MainSheet.Range("Q1").Resize(UBound(arrFin), 1).value = arrFin
End Sub
 

Комментарии:

1. Привет, спасибо за ответ, но это не работает. После запуска кода он заполняет пробелы из первого столбца во второй столбец. Чтобы уточнить мою цель: причина, по которой я использую .PasteSpecial, состоит в том, чтобы «Пропустить пробелы», чтобы, если в первом столбце есть пробелы, а во втором столбце (в той же строке) есть текст, он НЕ стирал текст второго столбца. Однако, если в обоих есть текст, текст первого столбца переопределяет текст второго столбца.

2. @Стивен, пожалуйста, попробуйте обновленный код. Я использовал (по ошибке) arr , даже не объявленный, вместо arrCopy . Сначала я протестировал код с помощью arr , а затем подумал, что использование arrCopy будет более выразительным… Использование SkipBlanks в последовательных шагах может создать проблемы, если пустые ячейки не существуют в одной строке…

3. Я заметил, что arr и arrCopy отключены — я подумал, что, вероятно, вы это имели в виду, так что не беспокойтесь. Я думаю, что проблема с использованием метода массива заключается в том, что при построении массива он помещает «» внутри соответствующих индексов, поэтому, когда он изменяет значение второго столбца, он каждый раз помещает «» вместо того, чтобы пропускать пробел. Я пытаюсь поиграть с такими идеями, как «Если значение, если arrCopy = «» тогда» пропустите еще … » Можете ли вы помочь коду, чтобы он пропускал ввод значения массива, если оно пустое?

4. Я нашел решение и ввел его в ваш пост, чтобы отметить его как правильный ответ. После того, как правка будет одобрена, я отмечу ее как правильный ответ. Спасибо за вашу помощь!

5. @Стивен, если необходимо пропустить пустые ячейки, я адаптирую код, но не так, как вы пытались. Больше всего времени и ресурсов уходит на вставку значения в ячейку. если корреляция между строками двух столбцов не имеет значения, я создам второй массив, чтобы получать только не пустые ячейки и сразу удалять его содержимое.

Ответ №3:

Редактировать:

Лучший ответ, который работал более надежно, чем мое оригинальное найденное решение, приведен ниже. Это адаптация некоторых советов из ответа ФанеДуру. Это решение более требовательно к ресурсам; однако на данный момент — оно выполняет задачу надежно (без сбоев). Я бы хотел, чтобы были лучшие ответы, чем циклическое повторение строк; однако это действительно отвечает на мою операцию. Спасибо вам за всю помощь!

     Sub copyColumnsArray()
 Dim lastR As Long, arrCopy
 
 lastR = MainSheet.Range("N" amp; rows.count).End(xlUp).row
 arrCopy = MainSheet.Range("N1:N" amp; lastR).value 

Dim ArrayIndex as Variant
Dim RowCount as String
RowCount = 1

For Each ArrayIndex in arrCopy
  If ArrayIndex = "" then
    RowCount = RowCount  1
    'Skip Blank
   else
    MainSheet.Range("P" RowCount).value = ArrayIndex
    RowCount = RowCount   1
   end if
 Next
 

 lastR = MainSheet.Range("R" amp; rows.count).End(xlUp).row
 arrCopy = MainSheet.Range("R1:R" amp; lastR).value

RowCount = 1

For Each ArrayIndex in arrCopy
  If ArrayIndex = "" then
    RowCount = RowCount  1
    'Skip Blank
   else
    MainSheet.Range("Q" RowCount).value = ArrayIndex
    RowCount = RowCount   1
   end if
 Next

End Sub
 

Комментарии:

1. Похоже, это вопрос необходимых ресурсов Excel, которые пытались вставить до завершения предыдущего процесса вставки. Это ненормальное поведение, VBA должен ждать сам по себе, пока операция не завершится. Лучшим решением должно быть использование массивов, которые вообще не используют буфер обмена и потребляют гораздо меньше ресурсов Excel. Я опубликовал фрагмент кода, способный заменить ваш, более стабильный и быстрый.