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