К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как удалить найденные строки в таблице значений 1С

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

Таблица значений в 1С — один из самых используемых объектов для промежуточного хранения и обработки данных. Рано или поздно возникает задача: найти строки, удовлетворяющие условию, и удалить их из таблицы. У начинающих разработчиков эта операция часто вызывает ошибки — например, пропуск строк или падение цикла из-за изменения коллекции во время обхода.

Есть два рабочих подхода: удаление через метод НайтиСтроки() с последующим обходом найденного массива и прямой обход таблицы с удалением «на лету». Первый способ безопаснее и читаемее, второй быстрее на больших объёмах, если обходить таблицу с конца. Выбор зависит от объёма данных и от того, нужно ли удалять строки по одному условию или по комбинации условий.

Материал ориентирован на встроенный язык 1С 8.3. Все примеры кода можно выполнять в модуле формы, общем модуле или внешней обработке — синтаксис идентичен.

Как устроено удаление строк из таблицы значений

Таблица значений — это индексированная коллекция. Каждая строка имеет индекс от 0 до Количество() - 1. Когда вы удаляете строку, индексы всех последующих строк сдвигаются на единицу. Именно это свойство становится источником большинства ошибок: если удалять строки в прямом цикле Для Каждого или по нарастающему индексу, часть строк будет пропущена.

Для удаления предусмотрены два метода таблицы значений: Удалить(Строка) — принимает сам объект строки, и Удалить(Индекс) — принимает числовой индекс. Оба варианта равнозначны по результату, отличается только способ адресации.

Дополнительно существует метод Очистить(), который удаляет все строки таблицы целиком. Он полезен, когда условие отбора фактически охватывает всё содержимое, — в этом случае не нужно искать и удалять строки по одной.

Удаление строк через НайтиСтроки — основной способ

Метод НайтиСтроки(ПараметрыОтбора) возвращает массив строк, удовлетворяющих отбору. Ключевое преимущество: массив — это отдельная коллекция, не связанная с индексацией таблицы. Удаление строк из таблицы никак не влияет на обход массива, поэтому цикл работает предсказуемо.

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

Отбор = Новый Структура;

Отбор.Вставить("Номенклатура", ИскомаяНоменклатура);

НайденныеСтроки = ТаблицаТоваров.НайтиСтроки(Отбор);

Для Каждого Строка Из НайденныеСтроки Цикл

ТаблицаТоваров.Удалить(Строка);

КонецЦикла;

Отбор по нескольким условиям выглядит аналогично — просто добавьте ключи в структуру. Например, удалить строки с конкретным складом и нулевым количеством:

Отбор = Новый Структура;

Отбор.Вставить("Склад", СкладСписания);

Отбор.Вставить("Количество", 0);

Для Каждого Строка Из ТаблицаТоваров.НайтиСтроки(Отбор) Цикл

ТаблицаТоваров.Удалить(Строка);

КонецЦикла;

1c
НайденныеСтроки = ТЗ.НайтиСтроки(Новый Структура("Количество", 0));
Для Каждого Строка Из НайденныеСтроки Цикл
    ТЗ.Удалить(Строка);
КонецЦикла;

Удаление при обходе таблицы с конца

Если условие сложное и его нельзя выразить структурой отбора (например, сравнение «меньше», «не равно», проверка нескольких полей через «ИЛИ»), приходится обходить таблицу вручную. Чтобы сдвиг индексов не ломал логику, обход выполняют с конца — от последней строки к первой.

Для Индекс = 1 - ТаблицаТоваров.Количество() По 0 Цикл

Инд = -Индекс;

Строка = ТаблицаТоваров[Инд];

Если Строка.Количество < 0 ИЛИ Строка.Пометка Тогда

ТаблицаТоваров.Удалить(Инд);

КонецЕсли;

КонецЦикла;

Обратите внимание на приём с отрицательным индексом: диапазон 1 - Количество() По 0 корректно срабатывает, даже когда таблица пуста, — цикл просто не выполнится. Более читаемый вариант — цикл Пока с уменьшением счётчика:

Инд = ТаблицаТоваров.Количество() - 1;

Пока Инд >= 0 Цикл

Если ТаблицаТоваров[Инд].Сумма = 0 Тогда

ТаблицаТоваров.Удалить(Инд);

КонецЕсли;

Инд = Инд - 1;

КонецЦикла;

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

Классическая ошибка выглядит так:

// ТАК ДЕЛАТЬ НЕЛЬЗЯ

Для Каждого Строка Из ТаблицаТоваров Цикл

Если Строка.Количество = 0 Тогда

ТаблицаТоваров.Удалить(Строка);

КонецЕсли;

КонецЦикла;

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

Та же проблема возникает при прямом обходе по индексу от 0 вверх с удалением через Удалить(Инд): после удаления все последующие строки сдвигаются влево, и цикл перескакивает через одну строку. Если всё же нужен прямой обход, после удаления уменьшайте индекс на единицу, но обход с конца — решение проще и надёжнее.

Типичные ошибки
01
Удаление строк в цикле «Для Каждого» по самой таблице — часть строк пропускается без ошибки
02
Отбор по значению несовпадающего типа: строка «5» не равна числу 5, НайтиСтроки вернёт пустой массив
03
Обход по индексу от нуля вверх с удалением — пропуск строк из-за сдвига индексов
04
Попытка удалить строку, уже удалённую ранее, — возникает исключение
05
Использование Найти() вместо НайтиСтроки() — удаляется только первая найденная строка, а не все

Сравнение способов удаления

У каждого подхода есть своя область применения. Для простых равенств удобнее НайтиСтроки, для сложных условий — обход с конца, для полной очистки — Очистить().

СпособКогда подходитОграничения
НайтиСтроки + Удалить(Строка)Отбор по равенству одного или нескольких полейТолько сравнение на равенство, только «И»
Обход с конца по индексуСложные условия: <, >, <>, «ИЛИ», вычисляемые проверкиКод менее читаем, легко ошибиться с индексами
Очистить()Удаление всех строк таблицыНельзя задать условие
Копирование в новую таблицу через запросБольшие объёмы, сложная фильтрацияТребует создания запроса и временной таблицы

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

Сравнение вариантов

НайтиСтроки + Удалить

Оптимально для отбора по равенству. Код короткий и безопасный, но нельзя задать условия «больше/меньше».

Обход с конца

Подходит для любых условий, включая вычисляемые. Требует аккуратности с индексами.

Запрос к таблице значений

Эффективен на больших объёмах и сложных отборах, но избыточен для простых задач.

Проверка результата и отладка

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

Было = ТаблицаТоваров.Количество();

// ... удаление ...

Остаток = ТаблицаТоваров.НайтиСтроки(Отбор).Количество();

Если Остаток > 0 Тогда

// условие сработало не полностью — ищем причину

КонецЕсли;

Если строки не удаляются, чаще всего виновато несовпадение типов: отбор по строковому представлению даты, числа или ссылки не находит значения другого типа. Проверьте тип колонки через ТаблицаТоваров.Колонки.Найти("Количество").ТипЗначения и тип искомого значения.

Контрольные точки

Как проверить результат

Повторный вызов НайтиСтроки тем же отбором
Норма

Возвращает пустой массив

Тревожный признак

Строки снова находятся — отбор не совпал по типу или значению

Количество строк после удаления
Норма

Уменьшилось ровно на число найденных строк

Тревожный признак

Уменьшилось меньше — вероятен пропуск строк в прямом цикле

Поведение на пустой таблице
Норма

Код выполняется без ошибок и ничего не удаляет

Тревожный признак

Ошибка обращения по индексу — не защищён обход

Когда удалять строки нельзя или не нужно

Если таблица значений является данными формы (реквизит формы типа «ТаблицаЗначений») и отображается пользователю, удаление строк немедленно отразится на экране. Убедитесь, что пользователь не редактирует таблицу в этот момент, иначе возможны рассинхронизация текущей строки и потеря фокуса ввода.

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

Если задача — не удалить «лишние» строки, а получить «правильные», рассмотрите обратный подход: создать новую таблицу и скопировать в неё только нужные строки через Выгрузить() с параметром отбора строк. Иногда это читаемее, чем удаление.

Маршрут решения

Как выбрать действие

Условие — равенство одного или нескольких полейИспользуйте НайтиСтроки со структурой отбора и Удалить(Строка)
Условие содержит &lt;, &gt;, &lt;&gt; или «ИЛИ»Обходите таблицу по индексу с конца и удаляйте через Удалить(Индекс)
Нужно удалить все строкиВызовите Очистить() — это быстрее и проще цикла
Строк десятки тысяч и отбор сложныйПередайте таблицу в запрос и выберите только нужные строки

Частые вопросы

Чем Найти() отличается от НайтиСтроки()?

Метод Найти(Значение, Колонка) возвращает только первую найденную строку или Неопределено. НайтиСтроки(Отбор) возвращает массив всех подходящих строк. Для удаления всех совпадений нужен именно НайтиСтроки; Найти подходит, только если гарантированно существует одна строка.

Почему НайтиСтроки не находит строки, хотя они есть?

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

Можно ли удалить строки по условию «не равно»?

Напрямую через НайтиСтроки — нет, отбор работает только на равенство. Варианты: обход таблицы с конца с проверкой условия в цикле, либо двухпроходная схема — найти строки, которые нужно оставить, скопировать их в новую таблицу и заменить исходную.

Удаляются ли строки из базы данных при удалении из таблицы значений?

Нет. Таблица значений существует только в памяти и не связана с базой данных. Удаление её строк никак не влияет на данные информационной базы. Чтобы изменения попали в базу, нужно отдельно записывать соответствующие объекты или наборы записей.

Что быстрее: удаление строк или выгрузка нужных в новую таблицу?

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

Безопасно ли удалять строки таблицы, связанной с элементом формы?

Технически да, но удаление сразу отражается в интерфейсе. Если пользователь в этот момент редактирует строку, текущая позиция может сброситься. Выполняйте массовое удаление по явной команде (кнопка, обработчик), а не в фоновых событиях формы.

Итог

Что важно запомнить

Для удаления найденных строк используйте НайтиСтроки() с обходом полученного массива — это безопасно и читаемо. Для сложных условий обходите таблицу по индексу с конца. Никогда не удаляйте строки в прямом цикле по самой таблице и проверяйте типы значений в отборе.