При разработке на платформе 1С:Предприятие одной из наиболее частых задач является обработка коллекций данных, в частности ТаблицыЗначений. Часто возникает ситуация, когда нам нужно изменить значения в одной колонке, основываясь на условии (отборе) в другой колонке. Например, в бухгалтерских задачах это может быть замена значения Субконто для всех строк, где КорСчет соответствует определенному счету.
Разберем подробно все способы решения этой задачи: от простого перебора до оптимизированных методов с использованием индексов и запросов. Проанализируем, какой метод лучше подходит для разных сценариев.
Рассмотрим самый распространенный и рекомендуемый для большинства случаев метод. Платформа 1С предоставляет встроенный метод НайтиСтроки(), который позволяет получить массив строк, соответствующих заданному условию.
Разберем по шагам, как это работает. Метод НайтиСтроки() принимает в качестве параметра структуру, где ключи — это имена колонок, а значения — то, что мы ищем. Важно понимать, что этот метод возвращает массив ссылок на строки исходной таблицы. Это значит, что изменяя строку в массиве, мы автоматически меняем её в самой таблице.
Посмотрим на пример кода:
// 1. Формируем структуру отбора
ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("КорСчет", ПланыСчетов.Хозрасчетный.ТоварыНаСкладах);
// 2. Находим нужные строки
НайденныеСтроки = ТЗ_Данных.НайтиСтроки(ПараметрыОтбора);
// 3. Обходим найденные строки и меняем значения
Для Каждыго СтрокаТЗ Из НайденныеСтроки Цикл
СтрокаТЗ.Субконто = НовоеЗначениеСубконто;
КонецЦикла;
Этот способ является максимально читаемым и эффективным для таблиц среднего размера. Его главное преимущество — простота реализации и отсутствие необходимости перебирать всю таблицу целиком (программно цикл выполняется только по тем строкам, которые прошли фильтр).
Проанализируем ситуацию, когда наша ТаблицаЗначений содержит десятки или сотни тысяч строк. В этом случае обычный вызов НайтиСтроки() может замедлиться, так как системе приходится сканировать таблицу. Чтобы ускорить этот процесс, мы можем использовать индексацию.
Индексы в ТаблицеЗначений работают аналогично индексам в базах данных. Мы указываем платформе, по каким колонкам мы будем часто выполнять поиск. Выясним, как это реализовать:
// Добавляем индекс по колонке отбора перед выполнением поиска
ТЗ_Данных.Индексы.Добавить("КорСчет");
// Теперь метод НайтиСтроки будет работать практически мгновенно
НайденныеСтроки = ТЗ_Данных.НайтиСтроки(Новый Структура("КорСчет", НужныйСчет));
Для Каждого Стр Из НайденныеСтроки Цикл
Стр.Субконто = НовоеЗначение;
КонецЦикла;
Важный момент: индексация требует времени и памяти на создание самого индекса. Поэтому добавляйте индексы только в том случае, если таблица действительно большая или поиск в цикле выполняется многократно.
Иногда логика изменения значений слишком сложная для простого перебора (например, новое значение нужно вычислить на основе данных из других таблиц базы данных). В таких случаях эффективнее использовать Запрос.
Посмотрим на алгоритм действий:
ТаблицуЗначений в запрос как параметр.ВЫБОР КОГДА....Пример реализации через запрос:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВТ_Данные.КорСчет,
| ВЫБОР
| КОГДА ВТ_Данные.КорСчет = &УсловиеСчета ТОГДА &НовоеСубконто
| ИНАЧЕ ВТ_Данные.Субконто
| КОНЕЦ КАК Субконто,
| ВТ_Данные.Количество,
| ВТ_Данные.Сумма
|ИЗ
| &ВТ_Данные КАК ВТ_Данные";
Запрос.УстановитьПараметр("ВТ_Данные", ТЗ_Данных);
Запрос.УстановитьПараметр("УсловиеСчета", ПланыСчетов.Хозрасчетный.Касса);
Запрос.УстановитьПараметр("НовоеСубконто", Справочники.СтатьиДвиженияДенежныхСредств.ПустаяСсылка());
РезультатЗапроса = Запрос.Выполнить();
ТЗ_Данных = РезультатЗапроса.Выгрузить();
Этот метод позволяет избежать написания циклов на встроенном языке, перенося обработку на уровень ядра системы. Это особенно полезно при работе с временными таблицами, когда данные уже находятся в контексте запроса.
В процессе обсуждения часто всплывает метод ЗаполнитьЗначения(). Рассмотрим его особенности. Метод ТЗ.ЗаполнитьЗначения(Значение, Колонка) заполняет все строки таблицы в указанной колонке одним и тем же значением.
К сожалению, у этого метода нет встроенного параметра "Отбор". Однако его можно скомбинировать с копированием строк:
// Копируем только нужные строки в новую таблицу
ТЗ_Временная = ТЗ_Данных.Скопировать(НайденныеСтроки);
// Массово меняем значение в колонке
ТЗ_Временная.ЗаполнитьЗначения(НовоеЗначение, "Субконто");
Но будьте осторожны: после этого вам придется либо удалять старые строки и добавлять новые, либо возвращать данные назад, что зачастую сложнее, чем просто использовать цикл по массиву из НайтиСтроки(). Поэтому ЗаполнитьЗначения() лучше использовать только тогда, когда нужно обновить всю колонку целиком.
Если вы работаете в модуле управляемой формы, важно помнить, что данные таблицы часто хранятся в типе ДанныеФормыКоллекция. У этого объекта нет метода НайтиСтроки() в том виде, в котором он есть у ТаблицыЗначений на сервере.
В этой ситуации мы рекомендуем следующий подход:
ТаблицуЗначений через РеквизитФормыВЗначение().ЗначениеВРеквизитФормы().Если же данных мало и нужно сделать это на клиенте, используйте обычный цикл Для Каждого с проверкой условия Если, так как клиент-серверные пересылки могут занять больше времени, чем простой перебор небольшой коллекции.
Мы проанализировали различные подходы к изменению данных в ТЗ с отбором. Самым сбалансированным решением является сочетание НайтиСтроки() и цикла Для Каждого. Для повышения производительности на больших объемах данных всегда используйте индексацию колонки, по которой строится отбор. Если же задача требует сложной аналитической замены, оптимальным выбором станет использование временных таблиц и запросов.