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

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

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

Способ 1. Использование цикла по результату запроса

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

Пример программного кода для реализации этого метода:


РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    НоваяСтрока = ТаблицаПриемник.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
КонецЦикла;

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

Способ 2. Использование типовых процедур БСП

Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), то изобретать велосипед не нужно. Разберем, какие инструменты предоставляют разработчики 1С. В современных версиях БСП (начиная с 3.0 и выше) существует процедура ДополнитьТаблицу в общем модуле ОбщегоНазначенияКлиентСервер.

Рассмотрим пример её использования:


// Сначала выгружаем результат запроса в промежуточную таблицу
ТаблицаИсточник = РезультатЗапроса.Выгрузить();

// Используем типовой метод для объединения
ОбщегоНазначенияКлиентСервер.ДополнитьТаблицу(ТаблицаИсточник, ТаблицаПриемник);

Проанализируем код самой процедуры внутри БСП. Она работает по схожему алгоритму с циклом, но оформлена как универсальный инструмент, который может принимать на вход не только таблицы значений, но и части деревьев значений или коллекции данных форм.


Процедура ДополнитьТаблицу(ТаблицаИсточник, ТаблицаПриемник) Экспорт
    Для Каждого СтрокаТаблицыИсточник Из ТаблицаИсточник Цикл
        ЗаполнитьЗначенияСвойств(ТаблицаПриемник.Добавить(), СтрокаТаблицыИсточник);
    КонецЦикла;
КонецПроцедуры

Способ 3. Объединение на уровне запроса (через Временные Таблицы)

Посмотрим на ситуацию с точки зрения производительности SQL. Если вы дополняете таблицу, которая сама была получена ранее, возможно, стоит пересмотреть архитектуру и объединить данные прямо в запросе. Этот метод считается наиболее профессиональным, так как он исключает медленные циклы на стороне встроенного языка 1С.

Алгоритм действий будет следующим:

  1. Поместим имеющуюся ТаблицаЗначений во временную таблицу (ВТ) внутри запроса с помощью МенеджерВременныхТаблиц.
  2. В этом же запросе выберем данные из базы.
  3. Используем оператор ОБЪЕДИНИТЬ ВСЕ для слияния данных из ВТ и реальных таблиц базы данных.
  4. Выгрузим итоговый результат обратно в ТаблицаЗначений.

Это позволит платформе оптимизировать работу с памятью и индексами на уровне СУБД.

Способ 4. Нестандартный подход с использованием «Вставить» и «ЗагрузитьКолонку»

Иногда в обсуждениях встречается метод, основанный на предварительном резервировании строк. Рассмотрим подробнее этот подход. Суть заключается в том, что мы сначала вставляем в начало или конец таблицы нужное количество пустых строк, а затем «заливаем» в них данные массивами по колонкам.

Пример кода (схематично):


// Добавляем пустые строки в начало
Для н = 1 По ТаблицаИсточник.Количество() Цикл
    ТаблицаПриемник.Вставить(0); 
КонецЦикла;

// Загружаем данные по колонкам
Для Каждого Колонка Из ТаблицаИсточник.Колонки Цикл
    МассивДанных = ТаблицаИсточник.ВыгрузитьКолонку(Колонка.Имя);
    ТаблицаПриемник.ЗагрузитьКолонку(МассивДанных, Колонка.Имя);
КонецЦикла;

Внимание: этот метод крайне опасен. Метод ЗагрузитьКолонку перезаписывает данные построчно, начиная с первой строки. Если количество строк в массиве и таблице не совпадает или если вы ошиблись с индексами при вставке, данные «съедут» и перемешаются. Мы не рекомендуем использовать этот способ, если только у вас нет специфической задачи по трансформации данных.

Оптимизация производительности: Индексы и Память

При работе с большими таблицами (десятки и сотни тысяч строк) добавление каждой новой строки через Добавить() может существенно замедляться. Выясним причину: если у таблицы значений определены Индексы, то при добавлении каждой строки 1С пытается пересчитать индекс.

Чтобы ускорить процесс, выполним следующие шаги:

  1. Сохраним и удалим индексы: Перед началом цикла дополнения таблицы удалите индексы у целевой таблицы.
  2. Дополним таблицу: Выполните объединение любым из вышеописанных способов.
  3. Восстановим индексы: После завершения всех операций добавления создайте индексы заново.

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

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

← На главную