Разработка и Конфигурация · 11 мин
Как удалить найденные строки в таблице значений 1С
Как правильно удалить найденные строки в таблице значений 1С: методы НайтиСтроки, обход с конца, типовые ошибки и готовые примеры кода на встроенном языке.
Таблица значений в 1С — один из самых используемых объектов для промежуточного хранения и обработки данных. Рано или поздно возникает задача: найти строки, удовлетворяющие условию, и удалить их из таблицы. У начинающих разработчиков эта операция часто вызывает ошибки — например, пропуск строк или падение цикла из-за изменения коллекции во время обхода.
Есть два рабочих подхода: удаление через метод НайтиСтроки() с последующим обходом найденного массива и прямой обход таблицы с удалением «на лету». Первый способ безопаснее и читаемее, второй быстрее на больших объёмах, если обходить таблицу с конца. Выбор зависит от объёма данных и от того, нужно ли удалять строки по одному условию или по комбинации условий.
Материал ориентирован на встроенный язык 1С 8.3. Все примеры кода можно выполнять в модуле формы, общем модуле или внешней обработке — синтаксис идентичен.
Как устроено удаление строк из таблицы значений
Таблица значений — это индексированная коллекция. Каждая строка имеет индекс от 0 до Количество() - 1. Когда вы удаляете строку, индексы всех последующих строк сдвигаются на единицу. Именно это свойство становится источником большинства ошибок: если удалять строки в прямом цикле Для Каждого или по нарастающему индексу, часть строк будет пропущена.
Для удаления предусмотрены два метода таблицы значений: Удалить(Строка) — принимает сам объект строки, и Удалить(Индекс) — принимает числовой индекс. Оба варианта равнозначны по результату, отличается только способ адресации.
Дополнительно существует метод Очистить(), который удаляет все строки таблицы целиком. Он полезен, когда условие отбора фактически охватывает всё содержимое, — в этом случае не нужно искать и удалять строки по одной.
Удаление строк через НайтиСтроки — основной способ
Метод НайтиСтроки(ПараметрыОтбора) возвращает массив строк, удовлетворяющих отбору. Ключевое преимущество: массив — это отдельная коллекция, не связанная с индексацией таблицы. Удаление строк из таблицы никак не влияет на обход массива, поэтому цикл работает предсказуемо.
Параметры отбора передаются структурой, где ключ — имя колонки, а значение — искомое значение. Можно указать несколько колонок одновременно, тогда отбор сработает по логическому «И».
Отбор = Новый Структура;
Отбор.Вставить("Номенклатура", ИскомаяНоменклатура);
НайденныеСтроки = ТаблицаТоваров.НайтиСтроки(Отбор);
Для Каждого Строка Из НайденныеСтроки Цикл
ТаблицаТоваров.Удалить(Строка);
КонецЦикла;
Отбор по нескольким условиям выглядит аналогично — просто добавьте ключи в структуру. Например, удалить строки с конкретным складом и нулевым количеством:
Отбор = Новый Структура;
Отбор.Вставить("Склад", СкладСписания);
Отбор.Вставить("Количество", 0);
Для Каждого Строка Из ТаблицаТоваров.НайтиСтроки(Отбор) Цикл
ТаблицаТоваров.Удалить(Строка);
КонецЦикла;
НайденныеСтроки = ТЗ.НайтиСтроки(Новый Структура("Количество", 0));
Для Каждого Строка Из НайденныеСтроки Цикл
ТЗ.Удалить(Строка);
КонецЦикла;Удаление при обходе таблицы с конца
Если условие сложное и его нельзя выразить структурой отбора (например, сравнение «меньше», «не равно», проверка нескольких полей через «ИЛИ»), приходится обходить таблицу вручную. Чтобы сдвиг индексов не ломал логику, обход выполняют с конца — от последней строки к первой.
Для Индекс = 1 - ТаблицаТоваров.Количество() По 0 Цикл
Инд = -Индекс;
Строка = ТаблицаТоваров[Инд];
Если Строка.Количество < 0 ИЛИ Строка.Пометка Тогда
ТаблицаТоваров.Удалить(Инд);
КонецЕсли;
КонецЦикла;
Обратите внимание на приём с отрицательным индексом: диапазон 1 - Количество() По 0 корректно срабатывает, даже когда таблица пуста, — цикл просто не выполнится. Более читаемый вариант — цикл Пока с уменьшением счётчика:
Инд = ТаблицаТоваров.Количество() - 1;
Пока Инд >= 0 Цикл
Если ТаблицаТоваров[Инд].Сумма = 0 Тогда
ТаблицаТоваров.Удалить(Инд);
КонецЕсли;
Инд = Инд - 1;
КонецЦикла;
Почему нельзя удалять строки в прямом цикле
Классическая ошибка выглядит так:
// ТАК ДЕЛАТЬ НЕЛЬЗЯ
Для Каждого Строка Из ТаблицаТоваров Цикл
Если Строка.Количество = 0 Тогда
ТаблицаТоваров.Удалить(Строка);
КонецЕсли;
КонецЦикла;
При удалении текущей строки внутренний итератор коллекции смещается, и следующая за удалённой строка пропускается. Если подряд идут две строки с нулевым количеством, вторая останется в таблице. Ошибка не вызывает исключения — код выполняется молча, что делает её особенно опасной в расчётах.
Та же проблема возникает при прямом обходе по индексу от 0 вверх с удалением через Удалить(Инд): после удаления все последующие строки сдвигаются влево, и цикл перескакивает через одну строку. Если всё же нужен прямой обход, после удаления уменьшайте индекс на единицу, но обход с конца — решение проще и надёжнее.
Сравнение способов удаления
У каждого подхода есть своя область применения. Для простых равенств удобнее НайтиСтроки, для сложных условий — обход с конца, для полной очистки — Очистить().
| Способ | Когда подходит | Ограничения |
|---|---|---|
| НайтиСтроки + Удалить(Строка) | Отбор по равенству одного или нескольких полей | Только сравнение на равенство, только «И» |
| Обход с конца по индексу | Сложные условия: <, >, <>, «ИЛИ», вычисляемые проверки | Код менее читаем, легко ошибиться с индексами |
| Очистить() | Удаление всех строк таблицы | Нельзя задать условие |
| Копирование в новую таблицу через запрос | Большие объёмы, сложная фильтрация | Требует создания запроса и временной таблицы |
Отдельно упомянем вариант с запросом: если таблица значений содержит десятки тысяч строк и нужен сложный отбор, можно передать её в запрос как временную таблицу и выбрать только нужные строки. Это часто быстрее поштучного удаления, хотя и требует больше кода.
Сравнение вариантов
Оптимально для отбора по равенству. Код короткий и безопасный, но нельзя задать условия «больше/меньше».
Подходит для любых условий, включая вычисляемые. Требует аккуратности с индексами.
Эффективен на больших объёмах и сложных отборах, но избыточен для простых задач.
Проверка результата и отладка
После удаления полезно убедиться, что таблица пришла в ожидаемое состояние. Простейшая проверка — сравнить количество строк до и после и повторно выполнить отбор тем же условием: он должен вернуть пустой массив.
Было = ТаблицаТоваров.Количество();
// ... удаление ...
Остаток = ТаблицаТоваров.НайтиСтроки(Отбор).Количество();
Если Остаток > 0 Тогда
// условие сработало не полностью — ищем причину
КонецЕсли;
Если строки не удаляются, чаще всего виновато несовпадение типов: отбор по строковому представлению даты, числа или ссылки не находит значения другого типа. Проверьте тип колонки через ТаблицаТоваров.Колонки.Найти("Количество").ТипЗначения и тип искомого значения.
Как проверить результат
Возвращает пустой массив
Строки снова находятся — отбор не совпал по типу или значению
Уменьшилось ровно на число найденных строк
Уменьшилось меньше — вероятен пропуск строк в прямом цикле
Код выполняется без ошибок и ничего не удаляет
Ошибка обращения по индексу — не защищён обход
Когда удалять строки нельзя или не нужно
Если таблица значений является данными формы (реквизит формы типа «ТаблицаЗначений») и отображается пользователю, удаление строк немедленно отразится на экране. Убедитесь, что пользователь не редактирует таблицу в этот момент, иначе возможны рассинхронизация текущей строки и потеря фокуса ввода.
В управляемых формах при передаче таблицы между клиентом и сервером дешевле выполнять удаление на сервере одним вызовом, чем удалять строки по одной в клиентском контексте — каждый серверный вызов из цикла замедляет работу в разы.
Если задача — не удалить «лишние» строки, а получить «правильные», рассмотрите обратный подход: создать новую таблицу и скопировать в неё только нужные строки через Выгрузить() с параметром отбора строк. Иногда это читаемее, чем удаление.
Как выбрать действие
Частые вопросы
Чем Найти() отличается от НайтиСтроки()?
Метод Найти(Значение, Колонка) возвращает только первую найденную строку или Неопределено. НайтиСтроки(Отбор) возвращает массив всех подходящих строк. Для удаления всех совпадений нужен именно НайтиСтроки; Найти подходит, только если гарантированно существует одна строка.
Почему НайтиСтроки не находит строки, хотя они есть?
Чаще всего причина в несовпадении типов: число не равно строке с тем же текстом, дата не равна её строковому представлению. Также проверьте имя колонки в структуре отбора — при опечатке платформа выдаст ошибку, но при лишних пробелах в значении отбор молча ничего не найдёт.
Можно ли удалить строки по условию «не равно»?
Напрямую через НайтиСтроки — нет, отбор работает только на равенство. Варианты: обход таблицы с конца с проверкой условия в цикле, либо двухпроходная схема — найти строки, которые нужно оставить, скопировать их в новую таблицу и заменить исходную.
Удаляются ли строки из базы данных при удалении из таблицы значений?
Нет. Таблица значений существует только в памяти и не связана с базой данных. Удаление её строк никак не влияет на данные информационной базы. Чтобы изменения попали в базу, нужно отдельно записывать соответствующие объекты или наборы записей.
Что быстрее: удаление строк или выгрузка нужных в новую таблицу?
Если удаляется небольшая доля строк, быстрее удалить их по месту. Если оставить нужно лишь малую часть большой таблицы, эффективнее создать новую таблицу и скопировать в неё нужные строки через Выгрузить() с отбором — это один вызов вместо множества удалений.
Безопасно ли удалять строки таблицы, связанной с элементом формы?
Технически да, но удаление сразу отражается в интерфейсе. Если пользователь в этот момент редактирует строку, текущая позиция может сброситься. Выполняйте массовое удаление по явной команде (кнопка, обработчик), а не в фоновых событиях формы.
Что важно запомнить
Для удаления найденных строк используйте НайтиСтроки() с обходом полученного массива — это безопасно и читаемо. Для сложных условий обходите таблицу по индексу с конца. Никогда не удаляйте строки в прямом цикле по самой таблице и проверяйте типы значений в отборе.