Найти в Дзене
Макрос решает

Макрос удаляет строки неправильно в Excel — 8 ошибок VBA и безопасный код

Макрос VBA удаляет не те строки, пропускает данные или ломает отчёт? Разбираем 8 частых ошибок при удалении строк в Excel и даём безопасные шаблоны кода. Макрос должен был просто удалить лишние строки. Пустые, дубли, старые записи, строки с ошибками, отменённые заявки или ненужные позиции из выгрузки. На первый взгляд задача элементарная: прошёл по таблице, проверил условие, удалил то, что не нужно. Никакой магии, никакой сложной логики, никакой многоэтажной автоматизации. Но после запуска начинается то, от чего у любого пользователя Excel внутри холодеет. Одни строки удалились, другие почему-то остались. Где-то исчезли нужные данные. Где-то таблица съехала. Иногда макрос удаляет каждую вторую подходящую строку, иногда пропускает целые блоки, а иногда работает «почти правильно», что ещё опаснее. Почти правильно — это худший вариант. Потому что если макрос упал с ошибкой, ты остановился и начал разбираться. Если Excel завис, ты понял, что что-то не так. А если макрос удалил 95% нужных с
Оглавление

Макрос VBA удаляет не те строки, пропускает данные или ломает отчёт? Разбираем 8 частых ошибок при удалении строк в Excel и даём безопасные шаблоны кода.

Макрос работает медленно в Excel — 9 ошибок VBA и ускорение кода

VBA неправильно находит последнюю строку в Excel — причины и безопасные решения

Макрос перезаписывает данные в Excel — 8 ошибок VBA и безопасное решение

Почему макрос в Excel работает медленно — 7 ошибок, которые тормозят VBA

Кнопка «Изменить» неактивна в Excel — 5 причин и точные решения

Макрос не запускается в Excel — 7 причин и решения

Макрос должен был просто удалить лишние строки. Пустые, дубли, старые записи, строки с ошибками, отменённые заявки или ненужные позиции из выгрузки. На первый взгляд задача элементарная: прошёл по таблице, проверил условие, удалил то, что не нужно. Никакой магии, никакой сложной логики, никакой многоэтажной автоматизации.

Но после запуска начинается то, от чего у любого пользователя Excel внутри холодеет. Одни строки удалились, другие почему-то остались. Где-то исчезли нужные данные. Где-то таблица съехала. Иногда макрос удаляет каждую вторую подходящую строку, иногда пропускает целые блоки, а иногда работает «почти правильно», что ещё опаснее.

Почти правильно — это худший вариант. Потому что если макрос упал с ошибкой, ты остановился и начал разбираться. Если Excel завис, ты понял, что что-то не так. А если макрос удалил 95% нужных строк, но 5% оставил или затёр пару важных записей, ошибка может уйти дальше в отчёт, сводную таблицу, письмо, акт или расчёт.

И вот здесь важно сказать честно: Excel не удаляет строки «как попало». Он делает ровно то, что написано в коде. Если строки пропускаются, удаляются не те записи или отчёт портится после запуска, причина почти всегда не в Excel, а в логике макроса. Особенно если код удаляет строки во время цикла.

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

Почему удаление строк — опасная операция

Удаление строки кажется простым действием только вручную. Когда ты сам выделяешь строку и нажимаешь «Удалить», ты видишь, что происходит. Ты контролируешь таблицу глазами. Если что-то пошло не так, можно сразу отменить действие через Ctrl + Z. Но макрос работает иначе. Он выполняет команды быстро, последовательно и без сомнений.

Главная особенность удаления строк в Excel — после удаления структура таблицы меняется. Все строки ниже поднимаются вверх. Номера строк меняются. То, что было строкой 15, становится строкой 14. То, что было строкой 16, становится строкой 15. И если в этот момент цикл продолжает идти сверху вниз, он может легко перескочить через строку, которая только что поднялась на место удалённой.

Именно из-за этого появляются странные ситуации: макрос должен удалить все пустые строки, но оставляет часть пустых строк внутри таблицы. Или должен удалить все строки со статусом «Отмена», но некоторые отменённые заявки остаются. Пользователь смотрит на код и не понимает: условие правильное, статус правильный, цикл есть, почему же не удалилось?

Проблема не в условии. Проблема в направлении обхода. Когда ты удаляешь строки сверху вниз, ты двигаешься по таблице, которая меняется прямо под ногами. Это как ремонтировать лестницу, стоя на ступеньках, которые сам же сейчас снимаешь. Можно, конечно, но шанс красиво улететь вниз очень высокий.

Ошибка №1. Удаление строк в цикле сверху вниз

Это самая частая и самая опасная ошибка. Она встречается в учебных примерах, старых макросах, файлах коллег и коде, который «работал годами, пока однажды не сломался». Цикл идёт от первой строки к последней и удаляет строки, подходящие под условие.

На первый взгляд код выглядит логично:

For i = 2 To lastRow
If Cells(i, "A").Value = "" Then*
Rows(i).Delete*

End If*
Next i

Здесь макрос проходит со второй строки до последней и удаляет строки, где в столбце A пусто. Для маленькой таблицы можно даже не сразу заметить проблему. Но если подряд идут две пустые строки, первая удалится, вторая поднимется на её место, а цикл перейдёт дальше. В итоге вторая пустая строка будет пропущена.

Пример простой. В строке 5 пусто, в строке 6 тоже пусто. Макрос дошёл до строки 5 и удалил её. Строка 6 стала строкой 5. Но счётчик цикла увеличился и пошёл к строке 6. Новая строка 5 осталась необработанной. Вот и весь «мистический» пропуск.

Правильное решение — удалять строки снизу вверх. Тогда удаление нижней строки никак не влияет на те строки, которые ещё предстоит проверить выше. Нумерация меняется только ниже текущей позиции, а цикл туда уже не вернётся.

For i = lastRow To 2 Step -1
If Cells(i, "A").Value = "" Then*
Rows(i).Delete*

End If*
Next i

Это базовое правило: если макрос удаляет строки в цикле, цикл должен идти снизу вверх. Не «желательно», не «иногда», а именно должен. Исключения бывают, но для обычных рабочих таблиц это главный безопасный вариант.

Ошибка №2. Не указывать лист явно

Вторая частая ошибка — удалять строки через Cells и Rows без указания конкретного листа. Пока активен нужный лист, всё работает. Но стоит пользователю перейти на другой лист, запустить макрос кнопкой или открыть файл в другом состоянии, и код начнёт удалять строки не там, где нужно.

Плохой вариант:

For i = lastRow To 2 Step -1
If Cells(i, "A").Value = "" Then*
Rows(i).Delete*

End If*
Next i

Здесь не видно, на каком листе выполняется проверка и удаление. VBA возьмёт активный лист. Если активен лист «Отчёт», удаление пойдёт там. Если активен лист «Архив», макрос начнёт чистить архив. Иногда это заканчивается не просто ошибкой, а настоящей потерей данных.

Правильный код всегда привязан к конкретному листу:

Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Данные")
For i = lastRow To 2 Step -1
If ws.Cells(i, "A").Value = "" Then*
ws.Rows(i).Delete*

End If*
Next i

Теперь макрос работает именно с листом «Данные», независимо от того, что открыто на экране. Это особенно важно, если файлом пользуются несколько человек, если макрос запускается кнопкой или если в книге много листов с похожей структурой.

В рабочих макросах удаление строк без явного указания листа — плохая практика. Можно забыть всё остальное, но это правило лучше оставить в голове железно: удаляешь строки — сначала зафиксируй лист. Иначе однажды макрос сработает не там, где ты ожидал.

Ошибка №3. Неправильно определять последнюю строку

Удаление строк почти всегда завязано на lastRow. Макрос должен понимать, до какой строки идти. Если последняя строка определена неверно, часть таблицы не попадёт в обработку или, наоборот, макрос уйдёт далеко вниз по пустым областям.

Часто используют стандартный вариант:

lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

Он хороший, если столбец A заполнен в каждой рабочей строке. Но если в столбце A есть пропуски, если данные начинаются не с него или если таблица устроена нестандартно, lastRow может оказаться неправильным.

Например, в столбце A стоит категория, которая заполняется только в первой строке блока, а в столбце B находится номер документа в каждой строке. Если искать последнюю строку по A, макрос может закончить работу раньше реального конца таблицы. Часть данных останется нетронутой, и ты будешь думать, что условие удаления не сработало.

Макрос решает

Правильнее искать последнюю строку по надёжному столбцу:

lastRow = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row

Но это не просто замена буквы. Нужно выбрать столбец, где значение есть в каждой строке: ID, дата, артикул, номер заявки, код клиента или другой обязательный признак. Если такого столбца нет, можно искать последнюю заполненную строку по всему листу.

Dim lastCell As Range
Set lastCell = ws.Cells.Find(What:="", After:=ws.Range("A1"), LookIn:=xlValues, SearchOrder:=xlByRows, SearchDirection:=xlPrevious)*
If lastCell Is Nothing Then
MsgBox "На листе нет данных для обработки.", vbExclamation*
Exit Sub*
End If
lastRow = lastCell.Row

Этот вариант полезен для хаотичных выгрузок, где данные могут быть в разных столбцах. Но и он требует здравого смысла: если где-то далеко внизу осталась случайная заметка, Find увидит её как последнюю строку. Поэтому таблицу лучше держать чистой.

Ошибка №4. Проверять пустоту слишком просто

Кажется, что пустую строку легко найти. Если ячейка пустая, значит её значение равно пустой строке. Но в Excel всё хитрее. Ячейка может выглядеть пустой, но содержать пробел, невидимый символ, формулу, которая возвращает пустую строку, или результат импорта из другой системы.

Плохой вариант:

If ws.Cells(i, "A").Value = "" Then
ws.Rows(i).Delete*
End If

Он сработает только для действительно пустого значения. Но если в ячейке есть пробел, визуально она будет пустой, а условие не выполнится. Пользователь увидит, что макрос «пропустил» пустую строку, хотя для VBA она не пустая.

Надёжнее использовать Trim и CStr:

If Trim(CStr(ws.Cells(i, "A").Value)) = "" Then
ws.Rows(i).Delete*
End If

Trim убирает лишние пробелы по краям, а CStr помогает безопасно привести значение к тексту. Это особенно полезно, если данные приходят из выгрузок, CRM, складских систем или файлов, которые кто-то вручную копировал из браузера.

Но даже этого иногда мало. Бывают невидимые неразрывные пробелы, которые Trim не убирает. Тогда можно дополнительно заменять Chr(160), который часто появляется при копировании из сайтов.

Dim cellText As String
cellText = Replace(CStr(ws.Cells(i, "A").Value), Chr(160), " ")
If Trim(cellText) = "" Then
ws.Rows(i).Delete*
End If

Такой код выглядит чуть длиннее, зато работает надёжнее с грязными данными. А в реальной автоматизации почти все данные в той или иной степени грязные. Excel — это не музей стерильных таблиц, это гараж, где всё надо проверять руками и инструментом.

Ошибка №5. Удалять строки по слишком широкому условию

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

Опасный вариант:

If InStr(1, ws.Cells(i, "C").Value, "отмена", vbTextCompare) > 0 Then
ws.Rows(i).Delete*
End If

Такой код удалит строку, если в столбце C где угодно встречается «отмена». Если там написано «не отменять», строка тоже может попасть под удаление. Если написано «отмена невозможна», тоже. Поэтому перед использованием InStr нужно понимать, нужен ли тебе поиск части текста или точное совпадение.

Если статус должен быть ровно «Отменено», лучше писать так:

If LCase(Trim(CStr(ws.Cells(i, "C").Value))) = "отменено" Then
ws.Rows(i).Delete*
End If

Здесь сравнение точное, но не зависит от регистра и лишних пробелов. Это безопаснее для статусов, категорий и признаков. Если же нужно удалять по нескольким статусам, лучше использовать Select Case.

Select Case LCase(Trim(CStr(ws.Cells(i, "C").Value)))
Case "отменено", "ошибка", "дубль"*
ws.Rows(i).Delete*
End Select

Такой код читается лучше. Через месяц ты откроешь макрос и сразу поймёшь, какие именно статусы удаляются. А когда условие спрятано в длинной строке с несколькими Or, вероятность ошибки выше.

Ошибка №6. Удалять строки без резервной копии

Удаление — операция разрушительная. Если макрос удалил строку, она исчезла из текущей версии файла. Да, иногда можно нажать Ctrl + Z, но после макросов отмена может быть недоступна или работать не так, как ожидается. А если файл сохранён после удаления, восстановить данные становится сложнее.

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

Простой вариант резервной копии:

Dim backupPath As String
If ThisWorkbook.Path <> "" Then
backupPath = ThisWorkbook.Path & "\backup_before_delete_" & Format(Now, "yyyymmdd_hhnnss") & ".xlsm"*
ThisWorkbook.SaveCopyAs backupPath*
End If

Такой код сохраняет копию файла рядом с текущей книгой. Если макрос удалит что-то не то, можно открыть backup и восстановить данные. Да, это добавляет несколько секунд. Но эти секунды дешевле, чем час восстановления отчёта или объяснение, почему пропали нужные строки.

Ещё один безопасный подход — не удалять строки сразу, а сначала помечать их. Например, в отдельном столбце поставить «Удалить», затем дать пользователю возможность проверить, и только потом запускать второй макрос для фактического удаления. Это особенно полезно, если условие сложное или данные важные.

If LCase(Trim(CStr(ws.Cells(i, "C").Value))) = "отменено" Then
ws.Cells(i, "G").Value = "Удалить"*
End If

Такой двухэтапный подход снижает риск. Сначала макрос показывает, что он собирается удалить. Потом человек проверяет. Потом удаление выполняется уже осознанно. Для критичных файлов это намного лучше, чем сразу «рубить с плеча».

Ошибка №7. Работать с фильтром неправильно

Фильтры в Excel часто вводят в заблуждение. Пользователь видит только отфильтрованные строки и думает, что макрос будет работать только с ними. Но VBA может обрабатывать весь диапазон, включая скрытые строки, если явно не указать другое. В результате удаляются строки, которые пользователь на экране даже не видел.

Если задача — удалить только видимые строки после фильтрации, нужно работать с SpecialCells(xlCellTypeVisible). Но и здесь надо быть осторожным: если видимых строк нет, SpecialCells может вызвать ошибку.

Например, базовый подход:

Dim rngVisible As Range
On Error Resume Next
Set rngVisible = ws.Range("A2:A" & lastRow).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If rngVisible Is Nothing Then
MsgBox "Нет видимых строк для обработки.", vbExclamation*
Exit Sub*
End If

Но удалять строки через For Each по видимым ячейкам нужно аккуратно, потому что структура всё равно меняется. Часто лучше собрать номера строк в коллекцию или просто идти снизу вверх и проверять Hidden.

For i = lastRow To 2 Step -1
If ws.Rows(i).Hidden = False Then*
If LCase(Trim(CStr(ws.Cells(i, "C").Value))) = "отменено" Then*

ws.Rows(i).Delete*

End If*

End If*
Next i

Этот код удаляет только видимые строки, которые подходят под условие. Но важно понимать: Rows(i).Hidden может быть True не только из-за фильтра, но и из-за ручного скрытия строки. Если это критично, логику нужно уточнять под конкретный файл.

Главное правило: если на листе включён фильтр, нельзя просто писать обычный макрос удаления и надеяться, что он поймёт видимую область. VBA не обязан угадывать намерение пользователя. Ему нужно прямо сказать, работать со всеми строками или только с видимыми.

Ошибка №8. Удалять строки по одной в огромной таблице

Удаление строк по одной — не только рискованная, но и медленная операция. Каждый раз Excel перестраивает лист, сдвигает строки, обновляет формулы, пересчитывает зависимости и меняет структуру. Если удалить 5000 строк по одной, макрос может работать очень долго.

Иногда это нормально, если строк мало. Но если таблица большая, лучше использовать другой подход: не удалять строки сразу, а собрать диапазон для удаления и удалить его одним действием. Это ускоряет работу, но требует аккуратности.

Пример подхода через Union:

Dim deleteRange As Range
For i = 2 To lastRow
If LCase(Trim(CStr(ws.Cells(i, "C").Value))) = "отменено" Then*
If deleteRange Is Nothing Then*

Set deleteRange = ws.Rows(i)*

Else*

Set deleteRange = Union(deleteRange, ws.Rows(i))*

End If*

End If*
Next i
If Not deleteRange Is Nothing Then deleteRange.Delete

Этот способ собирает строки и удаляет их в конце. Но у Union есть ограничения: если диапазонов очень много, работа тоже может стать тяжёлой. Поэтому для больших таблиц иногда лучше не удалять строки, а создать новую таблицу только из нужных данных. Это часто быстрее и безопаснее.

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

Макрос решает

Но для большинства обычных задач безопасный цикл снизу вверх вполне подходит. Главное — отключить лишние процессы Excel и явно указать лист.

Безопасный шаблон удаления пустых строк

Теперь соберём рабочий вариант. Он удаляет пустые строки по выбранному столбцу, идёт снизу вверх, явно указывает лист, создаёт резервную копию, отключает лишние процессы Excel и возвращает настройки даже при ошибке.

Sub DeleteEmptyRowsSafely()
Dim ws As Worksheet*
Dim lastRow As Long*
Dim i As Long*
Dim backupPath As String*
Dim oldCalc As XlCalculation*
On Error GoTo ErrHandler*
Set ws = ThisWorkbook.Worksheets("Данные")*
oldCalc = Application.Calculation*
If ThisWorkbook.Path <> "" Then*
backupPath = ThisWorkbook.Path & "\backup_before_delete_" & Format(Now, "yyyymmdd_hhnnss") & ".xlsm"*

ThisWorkbook.SaveCopyAs backupPath*

End If*
Application.ScreenUpdating = False*
Application.EnableEvents = False*
Application.Calculation = xlCalculationManual*
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row*
If lastRow < 2 Then*
MsgBox "Нет строк для проверки.", vbExclamation*

GoTo SafeExit*

End If*
For i = lastRow To 2 Step -1*
If Trim(Replace(CStr(ws.Cells(i, "A").Value), Chr(160), " ")) = "" Then*

ws.Rows(i).Delete*

End If*

Next i*
MsgBox "Удаление пустых строк завершено.", vbInformation*
SafeExit:
Application.ScreenUpdating = True*
Application.EnableEvents = True*
Application.Calculation = oldCalc*
Exit Sub*
ErrHandler:
MsgBox "Ошибка: " & Err.Description, vbCritical*
Resume SafeExit*
End Sub

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

Обрати внимание на oldCalc. Макрос запоминает текущий режим расчёта и возвращает именно его, а не навязывает автоматический пересчёт. Это аккуратнее по отношению к чужим рабочим файлам.

Безопасный шаблон удаления строк по статусу

Теперь второй сценарий: удалить строки, где в столбце C стоит статус «Отменено», «Дубль» или «Ошибка». Такой макрос часто нужен для очистки выгрузок перед отчётом.

Sub DeleteRowsByStatusSafely()
Dim ws As Worksheet*
Dim lastRow As Long*
Dim i As Long*
Dim statusText As String*
Dim deletedCount As Long*
Dim oldCalc As XlCalculation*
On Error GoTo ErrHandler*
Set ws = ThisWorkbook.Worksheets("Данные")*
oldCalc = Application.Calculation*
Application.ScreenUpdating = False*
Application.EnableEvents = False*
Application.Calculation = xlCalculationManual*
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row*
If lastRow < 2 Then*
MsgBox "Нет данных для обработки.", vbExclamation*

GoTo SafeExit*

End If*
For i = lastRow To 2 Step -1*
statusText = LCase(Trim(CStr(ws.Cells(i, "C").Value)))*

Select Case statusText*

Case "отменено", "дубль", "ошибка"*

ws.Rows(i).Delete*

deletedCount = deletedCount + 1*

End Select*

Next i*
MsgBox "Удалено строк: " & deletedCount, vbInformation*
SafeExit:
Application.ScreenUpdating = True*
Application.EnableEvents = True*
Application.Calculation = oldCalc*
Exit Sub*
ErrHandler:
MsgBox "Ошибка: " & Err.Description, vbCritical*
Resume SafeExit*
End Sub
Макрос решает

Здесь важно, что макрос не удаляет по расплывчатому совпадению. Он проверяет очищенный текст статуса и сравнивает его с конкретными значениями. Это снижает риск удалить строку, где слово «ошибка» встречается в комментарии, но сама запись должна остаться.

Также макрос считает, сколько строк удалено. Пользователь видит результат. Если ожидалось удалить 20 строк, а макрос удалил 2000, это повод остановиться и проверить резервную копию. Сообщение о результате — не украшение, а элемент контроля.

Вариант без удаления: пометить строки для проверки

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

Sub MarkRowsBeforeDelete()
Dim ws As Worksheet*
Dim lastRow As Long*
Dim i As Long*
Dim statusText As String*
Set ws = ThisWorkbook.Worksheets("Данные")*
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row*
For i = 2 To lastRow*
statusText = LCase(Trim(CStr(ws.Cells(i, "C").Value)))*

Select Case statusText*

Case "отменено", "дубль", "ошибка"*

ws.Cells(i, "G").Value = "Удалить"*

ws.Rows(i).Interior.Color = RGB(255, 235, 235)*

End Select*

Next i*
MsgBox "Строки для удаления помечены. Проверьте результат перед удалением.", vbInformation*
End Sub

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

После проверки можно запускать второй макрос, который удаляет строки с пометкой «Удалить». И снова — снизу вверх.

Sub DeleteMarkedRows()
Dim ws As Worksheet*
Dim lastRow As Long*
Dim i As Long*
Set ws = ThisWorkbook.Worksheets("Данные")*
lastRow = ws.Cells(ws.Rows.Count, "G").End(xlUp).Row*
For i = lastRow To 2 Step -1*
If LCase(Trim(CStr(ws.Cells(i, "G").Value))) = "удалить" Then*

ws.Rows(i).Delete*

End If*

Next i*
MsgBox "Помеченные строки удалены.", vbInformation*
End Sub

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

Как проверить, что макрос удалил всё правильно

После удаления строк нельзя просто радоваться сообщению «Готово». Нужно проверить результат. Хороший макрос сам должен помогать в этой проверке: показывать количество удалённых строк, создавать резервную копию, а при необходимости вести журнал.

Минимальная проверка — посчитать количество строк до и после.

Dim rowsBefore As Long
Dim rowsAfter As Long
rowsBefore = lastRow
'удаление строк
rowsAfter = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
MsgBox "Было строк: " & rowsBefore & vbCrLf & "Стало строк: " & rowsAfter, vbInformation

Так пользователь понимает масштаб изменений. Если было 5000 строк, стало 4990 — удалено 10. Если стало 1200 — нужно проверить, не слишком ли широким было условие.

Можно сделать ещё лучше: перед удалением считать строки, которые подходят под условие, и показать предупреждение.

If deletedCount > 100 Then
If MsgBox("Будет удалено много строк: " & deletedCount & ". Продолжить?", vbYesNo + vbQuestion) = vbNo Then*
GoTo SafeExit*

End If*
End If

Такой порог можно подстроить под файл. Для маленькой таблицы 100 строк — много. Для выгрузки на 50000 строк — нормально. Главное, что макрос начинает вести себя как ответственный помощник, а не как бездумный нож.

Что делать, если макрос уже удалил лишнее

Если ты запустил макрос и понял, что удалены не те строки, главное — не сохранять файл поверх старой версии. Сначала попробуй Ctrl + Z, но после макросов это не всегда доступно. Если была резервная копия, открой её и восстанови данные. Если файл хранится в OneDrive, Google Drive или корпоративном облаке, проверь историю версий.

Если резервной копии нет, остаются только косвенные способы: найти исходную выгрузку, запросить файл заново, восстановить из письма, из архива или из другого отчёта. Это неприятно, долго и часто невозможно полностью. Именно поэтому резервная копия перед массовым удалением — не украшение, а обязательная часть нормального макроса.

После восстановления обязательно разберись, почему ошибка произошла. Не запускай тот же код снова с надеждой, что «в этот раз повезёт». Проверь направление цикла, условие удаления, lastRow, лист, фильтры, пустые значения и формат данных. Макрос не исправится сам. Если логика неверная, он повторит ошибку.

Чек-лист перед запуском макроса удаления

Перед тем как запускать макрос, который удаляет строки, проверь восемь пунктов. Первый: лист указан явно. Второй: lastRow определяется по надёжному столбцу. Третий: цикл удаления идёт снизу вверх. Четвёртый: условие удаления точное, а не слишком широкое.

Пятый: пустые значения проверяются через Trim, а при необходимости учитываются неразрывные пробелы. Шестой: если включён фильтр, макрос понимает, работать со всеми строками или только с видимыми. Седьмой: перед удалением создаётся резервная копия или хотя бы есть пометка строк. Восьмой: после выполнения пользователь видит, сколько строк удалено.

Если хотя бы один пункт не выполнен, макрос может работать, но доверять ему рано. В VBA опасны не только ошибки, которые останавливают код. Опаснее ошибки, которые тихо дают неправильный результат.

В Телеграме я выкладываю готовые файлы и шаблоны VBA, которые можно использовать без ручной сборки:

безопасное удаление строк, работа с lastRow, защита от перезаписи, ускорение макросов, обработка выгрузок и проверка данных перед изменением.

Если хочешь забирать именно рабочие инструменты, а не только читать разборы, подписывайся

Итог

Если макрос удаляет строки неправильно, причина почти всегда находится в одном из восьми мест: цикл идёт сверху вниз, лист не указан явно, lastRow определён неверно, пустота проверяется слишком просто, условие удаления слишком широкое, фильтр не учтён, нет резервной копии или удаление выполняется слишком грубо для большой таблицы.

Удаление строк — операция, где нельзя писать «на глаз». Код должен быть точным, спокойным и предсказуемым. Он должен понимать, какой лист обрабатывает, до какой строки идёт, какие строки удаляет, почему удаляет и что делать, если что-то пошло не так.

Excel не обязан угадывать, какие данные важны. Он выполнит команду буквально. Поэтому задача хорошего макроса — не просто удалить строки, а удалить только те строки, которые действительно нужно удалить. И сделать это так, чтобы отчёт после запуска стал чище, а не опаснее.

Макрос решает

📁 Я собрал продукт-файл:

— 7 готовых макросов — удаление пустых строк — удаление по условию — безопасное удаление — диагностика ошибок — чек-лист перед запуском

👉 вставил → работает → не ломаешь файл

Скачать

Макрос работает медленно в Excel — 9 ошибок VBA и ускорение кода

VBA неправильно находит последнюю строку в Excel — причины и безопасные решения

Макрос перезаписывает данные в Excel — 8 ошибок VBA и безопасное решение

Почему макрос в Excel работает медленно — 7 ошибок, которые тормозят VBA

Кнопка «Изменить» неактивна в Excel — 5 причин и точные решения

Макрос не запускается в Excel — 7 причин и решения