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

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

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

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

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

Для этого у объекта ТаблицаЗначений есть несколько методов: Удалить(), Очистить(), а также связка НайтиСтроки() с последующим удалением. У каждого подхода есть свои ограничения, а неправильное удаление внутри цикла — классический источник ошибок, когда часть строк «проскакивает» и остаётся в таблице.

Ниже разобраны все рабочие способы с примерами кода, объяснено, почему нельзя удалять строки в прямом цикле Для Каждого, и показано, как проверить результат.

Основной метод Удалить() — по строке и по индексу

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

// Удаление по индексу (первая строка)

ТЗ.Удалить(0);

// Удаление конкретной строки

СтрокаКУдалению = ТЗ[5];

ТЗ.Удалить(СтрокаКУдалению);

Удаление по индексу удобно, когда позиция строки известна заранее — например, нужно убрать последнюю строку с итогом: ТЗ.Удалить(ТЗ.Количество() - 1). Удаление по ссылке на строку применяют, когда строка получена из другого места — из Найти(), НайтиСтроки() или передана параметром в процедуру.

Важно помнить: если передать в Удалить() индекс, которого нет в таблице (например, индекс равен количеству строк), платформа выдаст ошибку «Индекс находится за границами массива». Поэтому перед удалением по индексу полезно проверять границы.

Удаление строк по условию через НайтиСтроки()

Чаще всего нужно удалить не одну известную строку, а все строки, подходящие под условие: с пустым количеством, с определённым контрагентом, с нулевой суммой. Для этого используют связку НайтиСтроки() и Удалить().

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

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

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

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

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

КонецЦикла;

Метод НайтиСтроки() возвращает массив строк, и этот массив не связан с таблицей «живой» ссылкой на позиции — это копия ссылок на сами строки. Поэтому удалять строки в цикле по этому массиву безопасно: удаление из таблицы не влияет на содержимое массива.

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

Порядок действий при удалении по условию
  1. 1
    Сформируйте структуру отбора: Новый Структура("Поле", Значение)
  2. 2
    Получите массив строк: ТЗ.НайтиСтроки(Отбор)
  3. 3
    Пройдите по массиву циклом и удалите каждую строку методом ТЗ.Удалить(СтрокаТЗ)
  4. 4
    Проверьте результат: выведите ТЗ.Количество() до и после удаления

Почему нельзя удалять строки в цикле «Для Каждого»

Самая частая ошибка новичков — попытка удалить строки прямо в цикле обхода таблицы:

// ТАК ДЕЛАТЬ НЕЛЬЗЯ — часть строк будет пропущена

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

Если СтрокаТЗ.Сумма = 0 Тогда

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

КонецЕсли;

КонецЦикла;

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

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

// Вариант 1: обход с конца

Для Инд = 1 По ТЗ.Количество() Цикл

СтрокаТЗ = ТЗ[ТЗ.Количество() - Инд];

Если СтрокаТЗ.Сумма = 0 Тогда

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

КонецЕсли;

КонецЦикла;

// Вариант 2: сначала собрать, потом удалить

КУдалению = Новый Массив;

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

Если СтрокаТЗ.Сумма = 0 Тогда

КУдалению.Добавить(СтрокаТЗ);

КонецЕсли;

КонецЦикла;

Для Каждого СтрокаТЗ Из КУдалению Цикл

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

КонецЦикла;

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

Удаление всех строк: Очистить() и создание новой таблицы

Когда нужно удалить все строки, но сохранить структуру колонок, используют метод Очистить():

ТЗ.Очистить(); // строк удалено, колонки остались

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

Альтернатива — присвоить переменной новую пустую таблицу: ТЗ = Новый ТаблицаЗначений;. Но здесь есть тонкость: если на старую таблицу ссылаются другие переменные, реквизиты формы или она передана в процедуру по ссылке, то замена переменной не очистит исходный объект — остальные ссылки продолжат указывать на старые данные. Очистить() в этом смысле надёжнее, потому что изменяет сам объект.

Сравнение способов очистки

ТЗ.Очистить()

Удаляет все строки, сохраняет колонки и все внешние ссылки на объект. Подходит почти всегда.

ТЗ = Новый ТаблицаЗначений

Создаёт новый пустой объект без колонок. Старые ссылки на прежнюю таблицу продолжают работать со старыми данными.

Цикл с Удалить()

Избыточен для полной очистки — медленнее и длиннее. Оправдан только при выборочном удалении.

Удаление дублей и сложные условия

Типовая задача — оставить в таблице только уникальные строки по одной или нескольким колонкам. Готового метода «удалить дубли» у таблицы значений нет, но есть приём через свёртку или через вспомогательную таблицу.

Если строки должны отличаться только ключевыми полями, а числовые колонки можно просуммировать, подходит метод Свернуть():

// Оставляет уникальные комбинации Номенклатура+Склад,

// суммируя Количество и Сумму

ТЗ.Свернуть("Номенклатура, Склад", "Количество, Сумма");

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

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

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

Как выбрать способ удаления

Известна конкретная строка или её индексИспользуйте ТЗ.Удалить(Строка) или ТЗ.Удалить(Индекс)
Нужно удалить строки по точному совпадению полейНайтиСтроки(Отбор) + цикл по массиву с Удалить()
Условие сложное: диапазоны, «ИЛИ», сравненияОбратный цикл по индексу с проверкой или запрос с ГДЕ
Нужно удалить всёТЗ.Очистить() — сохранит колонки и ссылки на объект
Нужно убрать дубли с суммированиемТЗ.Свернуть() с указанием ключевых и суммируемых колонок

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

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

БылоСтрок = ТЗ.Количество();

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

ОсталосьСтрок = ТЗ.Количество();

Сообщить("Удалено строк: " + (БылоСтрок - ОсталосьСтрок));

// Контроль: строк с нулевой суммой не осталось

Проверка = ТЗ.НайтиСтроки(Новый Структура("Сумма", 0));

Если Проверка.Количество() > 0 Тогда

Сообщить("Внимание: остались строки с нулевой суммой!");

КонецЕсли;

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

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

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

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

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

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

Не изменилось — отбор не нашёл строк (проверьте имена колонок и типы)

Повторный НайтиСтроки по тому же условию
Норма

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

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

Строки найдены — удаление прошло частично, вероятно цикл по таблице с пропусками

Структура колонок после Очистить()
Норма

Колонки на месте, строк нет

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

Колонок нет — вместо Очистить() была создана новая таблица

Особенности для таблиц формы и больших объёмов

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

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

Итог

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

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

Часто задаваемые вопросы

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

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

НайтиСтроки возвращает пустой массив, хотя подходящие строки точно есть. В чём причина?

Чаще всего — опечатка в имени колонки в структуре отбора или несовпадение типов: например, в отборе строка «0», а в колонке число 0. Проверьте имя колонки и тип значения отбора, при необходимости приведите тип явно.

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

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

Чем Очистить() отличается от присваивания новой пустой таблицы?

Очистить() удаляет строки в существующем объекте, сохраняя колонки и все внешние ссылки на него. Присваивание ТЗ = Новый ТаблицаЗначений создаёт другой объект — старые ссылки продолжат указывать на прежнюю таблицу со старыми данными.

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

Пройдите таблицу обратным циклом по индексу, запоминая встреченные ключи в соответствии: если комбинация значений ключевых полей уже встречалась — удаляйте строку. Метод Свернуть() здесь не подойдёт, так как он агрегирует числовые колонки.

Почему после удаления в цикле «Для Каждого» часть строк осталась?

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