Удаление строк программно: таблица значений, табличная часть, макет и записи базы
Содержание
Строку из таблицы значений в 1С удаляют методом Удалить(): ТЗ.Удалить(Строка) или ТЗ.Удалить(Индекс). Так же работают табличные части документов и коллекции данных формы. Если строк несколько, обходите таблицу с конца или сначала соберите строки в массив, а потом удаляйте. Удаление прямо внутри Для Каждого пропускает строки.
Для табличного документа (печатной формы) нужен другой метод — УдалитьОбласть(). В запросе строки не удаляют вовсе: язык запросов только читает данные. Ниже код для каждого вида «таблицы» в 1С:Предприятии 8.3, который можно вставить в модуль из Конфигуратора и проверить.
Таблица значений: Удалить, Очистить и отбор копированием
Таблица значений живёт в памяти. Удаление из неё ничего не меняет в базе, поэтому здесь можно экспериментировать спокойно.
Метод Удалить() принимает один параметр: саму строку (СтрокаТаблицыЗначений) или её индекс. Индексы начинаются с нуля.
// Удалить первую строку
ТЗ.Удалить(0);
// Удалить конкретную строку
Стр = ТЗ.Найти("Иванов", "Фамилия");
Если Стр <> Неопределено Тогда
ТЗ.Удалить(Стр);
КонецЕсли;
// Удалить все строки, колонки остаются
ТЗ.Очистить();
📌 Чем отличаются способы:
- 🗑️
Удалить(Строка)— удобно, когда строка уже найдена черезНайти()или пришла из цикла; - 🔢
Удалить(Индекс)— удобно в цикле по счётчику; - 🧹
Очистить()— убирает все строки разом, структура колонок сохраняется; - 📋
Скопировать(Отбор)— не удаляет, а создаёт новую таблицу только с нужными строками.
Последний вариант часто проще всего. Если нужно оставить только активные строки, удобнее скопировать подходящие, чем удалять лишние:
Отбор = Новый Структура("Активна", Истина);
ТЗ = ТЗ.Скопировать(Отбор);
Скопировать() с отбором по структуре сравнивает только на равенство. Условие «сумма больше 1000» так не задать: для него нужен цикл (см. раздел про обход коллекций).
Удаление строк, найденных через НайтиСтроки
НайтиСтроки() возвращает массив строк, а не новую таблицу. Строки из этого массива можно удалять из исходной таблицы в обычном цикле: вы обходите массив, а меняется таблица.
Отбор = Новый Структура("Склад", СкладУдаляемый);
НайденныеСтроки = ТЗ.НайтиСтроки(Отбор);
Для Каждого Стр Из НайденныеСтроки Цикл
ТЗ.Удалить(Стр);
КонецЦикла;
Это самый короткий и надёжный способ удалить группу строк по точному совпадению значений.
Табличная часть документа и дерево значений
Табличная часть объекта (Объект.Товары) удаляет строки тем же методом Удалить(). После удаления НомерСтроки у оставшихся строк пересчитывается сам, вручную нумеровать ничего не нужно.
ДокОбъект = Ссылка.ПолучитьОбъект();
ДокОбъект.Товары.Удалить(0);
ДокОбъект.Записать();
У дерева значений строки удаляются из коллекции родителя: СтрокаДерева.Строки.Удалить(ПодчиненнаяСтрока). Верхний уровень — Дерево.Строки.Удалить(...). Вместе со строкой уходят все её подчинённые строки.
Как удалить строку табличной части на управляемой форме
На форме вы работаете не с самой табличной частью, а с данными формы (ДанныеФормыКоллекция). Элемент формы знает только идентификатор текущей строки, а не саму строку. Поэтому строку сначала получают по идентификатору:
&НаКлиенте
Процедура УдалитьТекущуюСтроку(Команда)
ИдСтроки = Элементы.Товары.ТекущаяСтрока;
Если ИдСтроки = Неопределено Тогда
Возврат;
КонецЕсли;
Стр = Объект.Товары.НайтиПоИдентификатору(ИдСтроки);
Объект.Товары.Удалить(Стр);
Модифицированность = Истина;
КонецПроцедуры
Код работает на клиенте, серверный вызов не нужен.
💡 Программное изменение данных формы не всегда помечает форму изменённой. Строка Модифицированность = Истина гарантирует, что при закрытии 1С спросит про сохранение, и удаление не потеряется.
Удаление выделенных строк
Элементы.Товары.ВыделенныеСтроки — массив идентификаторов. Удаляя строки, вы меняете и выделение, поэтому сначала скопируйте идентификаторы в свой массив:
&НаКлиенте
Процедура УдалитьВыделенные(Команда)
Идентификаторы = Новый Массив;
Для Каждого Ид Из Элементы.Товары.ВыделенныеСтроки Цикл
Идентификаторы.Добавить(Ид);
КонецЦикла;
Для Каждого Ид Из Идентификаторы Цикл
Стр = Объект.Товары.НайтиПоИдентификатору(Ид);
Если Стр <> Неопределено Тогда
Объект.Товары.Удалить(Стр);
КонецЕсли;
КонецЦикла;
Модифицированность = Истина;
КонецПроцедуры
Если пользователю нужно просто удалить строку
руками, программировать ничего не нужно. В командной панели таблицы на форме есть стандартная команда удаления, работает и клавиша Delete. Код пишут, когда удаление идёт по условию или из обработки.
Табличный документ: удаляем строки печатной формы
Табличный документ (ТабличныйДокумент) — это не набор строк с колонками, а сетка ячеек. Здесь удаляют область целиком методом УдалитьОбласть() и указывают, куда сдвинуть оставшиеся ячейки.
// Удалить строки с 5-й по 7-ю, нижние строки поднимутся вверх
Область = ТабДок.Область("R5:R7");
ТабДок.УдалитьОбласть(Область, ТипСмещенияТабличногоДокумента.ПоВертикали);
📌 Что нужно знать:
- 📐
"R5:R7"— область строк целиком,"C2"— колонка,"R5C2:R7C4"— прямоугольник; - ↕️
ПоВертикалисдвигает ячейки вверх,ПоГоризонтали— влево; - 🧮 после удаления нумерация строк смещается: если удаляете несколько областей, идите снизу вверх;
- 🧹
ТабДок.Очистить()стирает весь документ, а не одну строку.
Чтобы удалить последнюю строку, номер берут из свойства ВысотаТаблицы:
Если ТабДок.ВысотаТаблицы > 0 Тогда
НомерПоследней = Формат(ТабДок.ВысотаТаблицы, "ЧГ=0");
Область = ТабДок.Область("R" + НомерПоследней);
ТабДок.УдалитьОбласть(Область, ТипСмещенияТабличногоДокумента.ПоВертикали);
КонецЕсли;
Формат(..., "ЧГ=0") здесь обязателен. Без него число больше 999 превратится в строку с неразрывным пробелом («1 024»), и имя области будет неверным.
💡 В печатных формах удаление обычно не лучший путь. Проще не выводить ненужную строку: проверить условие перед ТабДок.Вывести(ОбластьСтроки). Удаление оставьте для готовых документов, которые пришли извне, например загруженных из файла Excel.
Временные таблицы и запросы: удаления нет, есть отбор и УНИЧТОЖИТЬ
В языке запросов 1С нет команды DELETE. Запрос только читает данные. Поэтому «удалить строку из результата запроса» означает одно из трёх:
| Задача | Как решить | Где |
|---|---|---|
| Не получить лишние строки | Условие в ГДЕ или ИМЕЮЩИЕ | Текст запроса |
| Убрать временную таблицу целиком | УНИЧТОЖИТЬ ВТ_Имя | Пакет запроса |
| Убрать строки после выполнения | Результат.Выгрузить() и Удалить() по таблице значений | Код модуля |
Отбор в самом запросе почти всегда быстрее, чем выгрузка с последующей чисткой в цикле. СУБД отдаёт меньше данных, и сервер 1С не держит лишнее в памяти.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Номенклатура КАК Номенклатура,
| Остатки.КоличествоОстаток КАК Количество
|ПОМЕСТИТЬ ВТ_Остатки
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
|ГДЕ
| Остатки.КоличествоОстаток > 0
|;
|
|ВЫБРАТЬ
| ВТ_Остатки.Номенклатура,
| ВТ_Остатки.Количество
|ИЗ
| ВТ_Остатки КАК ВТ_Остатки
|;
|
|УНИЧТОЖИТЬ ВТ_Остатки";
Имя регистра в примере условное, подставьте своё.
Менеджер временных таблиц
Если временные таблицы живут в МенеджерВременныхТаблиц и переходят из запроса в запрос, удалить конкретную таблицу можно тем же УНИЧТОЖИТЬ в следующем запросе с этим менеджером. Все таблицы сразу освобождает МенеджерВТ.Закрыть().
Строку внутри временной таблицы удалить нельзя. Нужен другой состав — создайте новую временную таблицу запросом с нужным ГДЕ.
Удаление строк в цикле без пропусков
Главная ловушка — удалять строки внутри Для Каждого по той же коллекции. Ошибки не будет, но после удаления строки следующая сдвигается на её место, и цикл её проскакивает. Две подряд строки на удаление — одна останется.
Пример: в таблице 4 строки, удалить нужно 2-ю и 3-ю. Цикл удаляет 2-ю, 3-я встаёт на её место, цикл переходит к следующей позиции (бывшая 4-я). В итоге 3-я строка уцелела.
Способ 1. Обход с конца по индексу
При удалении меняются индексы только у строк после удалённой. Если идти от последней строки к первой, необработанные строки не сдвигаются.
Всего = ТЗ.Количество();
Для Сч = 1 По Всего Цикл
Индекс = Всего - Сч;
Стр = ТЗ[Индекс];
Если Стр.Сумма > 1000 Тогда
ТЗ.Удалить(Индекс);
КонецЕсли;
КонецЦикла;
Проверим на 4 строках: Всего = 4, индексы идут 3, 2, 1, 0. Удаление строки с индексом 2 не трогает строки 1 и 0, которые ещё впереди. Количество фиксируется до цикла в Всего и внутри не пересчитывается.
Способ 2. Сначала собрать, потом удалить
Этот вариант читается проще и подходит для любых коллекций, включая данные формы:
КУдалению = Новый Массив;
Для Каждого Стр Из ТЗ Цикл
Если Стр.Сумма > 1000 Тогда
КУдалению.Добавить(Стр);
КонецЕсли;
КонецЦикла;
Для Каждого Стр Из КУдалению Цикл
ТЗ.Удалить(Стр);
КонецЦикла;
| Способ | Когда брать | На что смотреть |
|---|---|---|
НайтиСтроки() + удаление | Отбор по точному равенству полей | Не подходит для «больше/меньше» |
| Обход с конца | Сложное условие, большие таблицы | Индексы с нуля, Всего до цикла |
| Массив к удалению | Нужна читаемость, данные формы | Лишний проход по таблице |
Скопировать(Отбор) | Оставить строки по равенству | Получается новая таблица |
| Условие в запросе | Данные берутся из базы | Лучший вариант по скорости |
Удаление записей из таблиц базы данных
Здесь «строка таблицы» — это уже запись в базе: элемент справочника, документ, запись регистра. Такие действия необратимы.
Перед массовым удалением из рабочей базы выгрузите копию: в Конфигураторе Администрирование → Выгрузить информационную базу (файл .dt) или через резервное копирование СУБД. Сначала проверьте код на копии.
Справочники и документы: пометка или сразу удаление
У объекта есть два пути:
- 🏷️
Объект.УстановитьПометкуУдаления(Истина)— мягкий вариант. Объект остаётся в базе, а окончательно его удаляет обработка удаления помеченных объектов с проверкой ссылок. В БП 3.0 она находится вАдминистрирование → Обслуживание, группа «Корректировка данных». - ❌
Объект.Удалить()— непосредственное удаление без проверки ссылок. Документы, которые ссылались на объект, получат «битые» ссылки вида<Объект не найден>.
// Мягко: пометить
Об = Ссылка.ПолучитьОбъект();
Об.УстановитьПометкуУдаления(Истина);
// Жёстко: удалить сразу (только если уверены, что ссылок нет)
Об = Ссылка.ПолучитьОбъект();
Об.Удалить();
Для непосредственного удаления у роли пользователя должно быть право «Удаление» на этот объект (право «Интерактивное удаление» относится к удалению руками из формы) — иначе код упадёт с ошибкой нарушения прав доступа. Под полными правами такой проблемы нет.
Регистры: запись пустого набора
Записи регистра удаляют набором записей. Установите отбор и запишите набор пустым — записи, попавшие под отбор, будут удалены:
Набор = РегистрыСведений.КурсыВалют.СоздатьНаборЗаписей();
Набор.Отбор.Валюта.Установить(ВалютаСсылка);
Набор.Отбор.Период.Установить(ДатаКурса);
Набор.Записать();
Без отбора Записать() пустого набора очистит весь регистр. Проверьте отбор дважды.
Для регистров, подчинённых регистратору (движения документа), отбор ставят по Регистратор. Правильнее же удалять движения через сам документ: отмена проведения убирает их штатно и не оставляет документ проведённым без движений.
💡 Для одной записи независимого регистра сведений удобен менеджер записи: заполнить измерения и период, вызвать Прочитать(), проверить Выбран() и вызвать Удалить().
Обработчики при удалении
При записи пустого набора и при Удалить() срабатывают подписки и обработчики ПередУдалением, ПередЗаписью. Иногда разработчики отключают их через ОбменДанными.Загрузка = Истина. Делайте так только в обработках переноса данных: проверки конфигурации при этом не выполняются, и в базе могут остаться несогласованные данные.
Ошибки при удалении строк и как их распознать
Отдельный случай — сообщение о нарушении прав при Удалить() у справочника или документа. Это не ошибка кода: у роли пользователя нет права удаления. Выполните операцию с сервера в привилегированном режиме или под пользователем с полными правами, если это допускает регламент.
Частые вопросы
Как удалить колонку из таблицы значений?
ТЗ.Колонки.Удалить("ИмяКолонки"). Значения этой колонки во всех строках пропадут.Можно ли удалить строку табличной части проведённого документа?
Как удалить пустые строки из таблицы значений?
ЗначениеЗаполнено() и удаляйте строку по индексу, если все поля пустые.Удаляет ли Очистить() таблицу значений целиком?
Почему после удаления строк табличной части номера строк идут без пропусков?
НомерСтроки у табличных частей пересчитывается автоматически. У таблицы значений такого поля нет: индекс просто сдвигается.