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

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Разберем частую проблему, с которой сталкиваются разработчики в 1С при работе с коллекциями. Когда выполняется последовательный вызов метода Удалить() для таблицы значений по индексам, результат может оказаться неожиданным. Проанализируем причину такого поведения и рассмотрим верные способы удаления строк как на уровне кода, так и на этапе выполнения запроса.

Почему при последовательном удалении строк возникают ошибки?

Выясним причину, по которой код вида Результат.Удалить(1); Результат.Удалить(2); работает не так, как ожидает программист.

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

Посмотрим на пример: если мы удаляем строку с индексом 1 (вторая строка), бывшая третья строка с индексом 2 моментально занимает освободившийся индекс 1. Вызывая следом Результат.Удалить(2), мы фактически удаляем элемент, который изначально был четвертым по счету (с индексом 3). В итоге часть нужных строк остается нетронутой, а лишние элементы удаляются со смещением.

Способ 1. Обход и удаление строк «снизу вверх» (с конца)

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

Рассмотрим пример кода с использованием цикла Пока:


НомерСтрокиТЗ = Результат.Количество() - 1;
Пока НомерСтрокиТЗ >= 0 Цикл
    СтрокаТЗ = Результат[НомерСтрокиТЗ];
    
    // Проверяем условие для удаления
    Если НеобходимостьУдаления(СтрокаТЗ) Тогда
        Результат.Удалить(СтрокаТЗ);
    КонецЕсли;
    
    НомерСтрокиТЗ = НомерСтрокиТЗ - 1;
КонецЦикла;

Обратим внимание: передача самого объекта строки СтрокаТЗ в метод Удалить() является наиболее надежным решением.

Способ 2. Предварительный сбор удаляемых строк в массив

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

Посмотрим, как реализовать этот алгоритм:


МассивУдаляемые = Новый Массив;

// Заполняем массив ссылками на удаляемые строки
Для Каждого СтрокаТЗ Из Результат Цикл
    Если УсловиеУдаления(СтрокаТЗ) Тогда
        МассивУдаляемые.Добавить(СтрокаТЗ);
    КонецЕсли;
КонецЦикла;

// Удаляем собранные строки из таблицы значений
Для Каждого СтрокаДляУдаления Из МассивУдаляемые Цикл
    Результат.Удалить(СтрокаДляУдаления);
КонецЦикла;

Важно помнить: напрямую удалять элементы из коллекции внутри цикла Для Каждого Строка Из ТЗ Цикл нельзя, так как это нарушает работу итератора платформы и приводит к пропуску строк.

Способ 3. Использование методов НайтиСтроки() и Скопировать()

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

Рассмотрим отбор через метод НайтиСтроки():


Отбор = Новый Структура("Статус", "Удалить");
МассивСтрок = Результат.НайтиСтроки(Отбор);

Для Каждого СтрокаИзМассива Из МассивСтрок Цикл
    Результат.Удалить(СтрокаИзМассива);
КонецЦикла;

Если же требуется сохранить лишь небольшую часть данных, эффективнее не удалять лишние элементы по одному, а скопировать нужные строки в новую таблицу с помощью метода Скопировать(). Метод Удалить() при каждом вызове физически сдвигает массив строк в памяти, поэтому пересборка таблицы через копирование работает значительно быстрее на больших объемах данных.

Способ 4. Перенос фильтрации на уровень запроса

Часто наиболее правильным решением является изменение логики самого запроса. Если лишние записи попадают в результат на этапе отбора из базы данных, целесообразно исключить их до выгрузки в таблицу значений. Это избавит от необходимости писать дополнительный код обработки в 1С и снизит нагрузку на сервер СУБД.

Рассмотрим основные приемы фильтрации в языке запросов 1С:

  1. Использование иерархии: Если позиции должны принадлежать конкретной группе номенклатуры, применим условие Номенклатура.Ссылка В ИЕРАРХИИ (&Группа) или проверку родителя Номенклатура.Родитель = &Группа.
  2. Исключающие условия: Для отсечения нежелательных строк добавим конструкцию ГДЕ НЕ Номенклатура.Наименование ПОДОБНО &ИсключаемыйШаблон.
  3. Экранирование спецсимволов: Если поиск выполняется по шаблону с использованием символов % или _, укажем оператор СПЕЦСИМВОЛ, например: ГДЕ Номенклатура.Наименование ПОДОБНО "%10~%%" СПЕЦСИМВОЛ "~".
← На главную