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

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

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

Как в 1С выгрузить результат запроса в таблицу значений: метод Выгрузить(), получение обхода результата, работа с колонками, типичные ошибки и примеры кода.

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

Механика проста: создаётся объект «Запрос», ему присваивается текст на встроенном языке запросов, при необходимости устанавливаются параметры, затем вызывается цепочка Запрос.Выполнить().Выгрузить(). На выходе разработчик получает таблицу значений с колонками, соответствующими полям выборки, и строками, соответствующим записям результата.

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

Базовый синтаксис: минимальный рабочий код

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

bsl
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Номенклатура,
| Номенклатура.Код КАК Код,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";

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

После выполнения этого кода переменная ТаблицаРезультат содержит таблицу значений с тремя колонками: «Номенклатура», «Код», «Наименование». Имена колонок соответствуют псевдонимам полей, указанным после ключевого слова КАК в тексте запроса. Если псевдоним не задан, платформа сформирует имя автоматически, и обращаться к такой колонке будет неудобно.

Обратите внимание: метод Выполнить() возвращает объект «РезультатЗапроса», а не таблицу. Сам по себе результат запроса не позволяет индексировать строки или передавать данные в табличное поле формы — для этого и нужна выгрузка. Частая цепочка записывается в одну строку: ТЗ = Запрос.Выполнить().Выгрузить();.

Установка параметров перед выгрузкой

Реальные запросы почти всегда содержат отборы. Параметры задаются через метод УстановитьПараметр() до вызова Выполнить(). Порядок вызовов важен: сначала текст, затем параметры, затем выполнение.

bsl
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Продажи.Номенклатура КАК Номенклатура,
| СУММА(Продажи.Количество) КАК Количество
|ИЗ
| РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК Продажи
|СГРУППИРОВАТЬ ПО
| Продажи.Номенклатура";

Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДатаСеанса()));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДатаСеанса()));

ТаблицаПродаж = Запрос.Выполнить().Выгрузить();

Если параметр объявлен в тексте запроса, но не установлен, при выполнении возникнет ошибка. Если параметр установлен, но не используется в тексте — платформа его проигнорирует, ошибки не будет. Для отборов по спискам значений параметру можно передать массив или список значений и использовать оператор В (&Список).

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

Обход результата: прямой, по группировкам, с иерархией

Метод Выгрузить() принимает необязательный параметр — тип обхода результата. От него зависит, что именно окажется в таблице значений, когда запрос содержит итоги (ИТОГИ) или иерархические выборки.

Тип обходаЧто попадает в таблицуКогда применять
Прямой (по умолчанию)Только детальные записи, строки итогов отсутствуютОбычные плоские выборки, обмен данными, расчёты по строкам
По группировкамСтроки итогов по группировкам и детальные записиКогда нужны промежуточные суммы в плоском виде
По группировкам с иерархиейДерево значений с вложенными строкамиИерархические отчёты, вывод на форму в виде дерева

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

bsl
// Плоская таблица без строк итогов
ТЗ = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.Прямой);

// Дерево значений с иерархией по группировкам
Дерево = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);

Структура таблицы значений после выгрузки

Колонки выгруженной таблицы формируются по полям выборки. Тип каждой колонки определяется типом соответствующего поля запроса: ссылочные поля сохраняют тип ссылки, числовые — тип «Число» с точностью из метаданных или результата агрегатной функции. Поля составного типа (например, Регистратор у регистра) дадут колонку составного типа.

Порядок колонок соответствует порядку полей в секции ВЫБРАТЬ. Порядок строк — порядок выборки: если в запросе нет секции УПОРЯДОЧИТЬ ПО, порядок строк не гарантирован и может меняться между выполнениями. Если дальнейшая логика зависит от порядка (например, нумерация строк или сравнение с эталоном), сортировку нужно задавать явно — либо в запросе, либо методом Сортировать() уже у таблицы значений.

Проверить структуру таблицы можно в отладчике через «Вычислить выражение»: ТаблицаРезультат.Колонки покажет список колонок, ТаблицаРезультат.Количество() — число строк. Полезно проверять количество строк сразу после выгрузки: ноль строк обычно означает, что отбор слишком строгий или параметры заданы неверно, а не что выгрузка «сломалась».

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

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

Количество строк таблицы
Норма

Соответствует ожидаемому числу записей по отбору

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

0 строк при заведомо существующих данных — проверьте параметры отбора

Имена колонок
Норма

Совпадают с псевдонимами полей из запроса

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

Колонки вида «Поле1», «Ссылка» без осмысленных имён — не заданы псевдонимы КАК

Тип возвращаемого значения
Норма

ТаблицаЗначений при прямом обходе

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

Ожидалась таблица, а получено дерево значений — задан обход с иерархией

Альтернатива: обход через Выбрать() без выгрузки

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

Выгрузить() или Выбрать()

Выгрузить() в таблицу значений

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

Обход через Выбрать()

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

Выгрузить() в дерево значений

Подходит для иерархических данных и вывода на форму. Ограничение — требуется рекурсивный обход, нет методов плоского поиска.

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

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

Типичные ошибки и ограничения

Типичные ошибки
01
Обращение к полям результата без Выгрузить() или Выбрать() — объект РезультатЗапроса не содержит строк напрямую, код падает с ошибкой
02
Ожидание таблицы при обходе ПоГруппировкамСИерархией — метод возвращает дерево значений, вызов Найти() приводит к ошибке
03
Выгрузка миллионов строк целиком — рост потребления памяти и риск аварийного завершения сеанса; для больших объёмов используйте Выбрать() или пакетную обработку
04
Отсутствие псевдонимов КАК у вычисляемых полей — колонки получают автогенерированные имена, и обращение ТЗ.Колонки.Найти("Сумма") возвращает Неопределено
05
Повторное выполнение запроса в цикле вместо одной выгрузки — многократное обращение к СУБД вместо поиска по уже выгруженной таблице

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

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

Практический сценарий: выгрузка и дальнейшая обработка

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

bsl
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Номенклатура КАК Номенклатура,
| Остатки.КоличествоОстаток КАК Остаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &Склад) КАК Остатки";
Запрос.УстановитьПараметр("Склад", ВыбранныйСклад);

ТаблицаОстатков = Запрос.Выполнить().Выгрузить();
ТаблицаОстатков.Индексы.Добавить("Номенклатура");

НайденнаяСтрока = ТаблицаОстатков.Найти(ИскомаяНоменклатура, "Номенклатура");
Если НайденнаяСтрока <> Неопределено Тогда
 Сообщить("Остаток: " + НайденнаяСтрока.Остаток);
КонецЕсли;

Здесь показаны сразу несколько приёмов: параметризованный отбор по складу на уровне виртуальной таблицы (это быстрее, чем отбор в секции ГДЕ), выгрузка в таблицу, добавление индекса для ускорения поиска и безопасная проверка результата Найти() на Неопределено.

Порядок действий
  1. 1
    Создайте объект Запрос и задайте текст с псевдонимами полей через КАК
  2. 2
    Установите все параметры, используемые в тексте запроса
  3. 3
    Выполните запрос и выгрузите результат: ТЗ = Запрос.Выполнить().Выгрузить()
  4. 4
    Проверьте количество строк и структуру колонок в отладчике
  5. 5
    При многократном поиске добавьте индекс по ключевой колонке
  6. 6
    Если результат иерархический — используйте обход ПоГруппировкамСИерархией и работайте с деревом значений

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

Чем отличается Выполнить() от Выгрузить()?

Метод Выполнить() отправляет запрос в СУБД и возвращает объект «РезультатЗапроса» — это не данные, а «указатель» на выборку. Метод Выгрузить() материализует результат в таблицу значений в памяти. Без Выгрузить() или Выбрать() получить строки результата нельзя.

Почему после выгрузки таблица пустая, хотя данные в базе есть?

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

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

Передайте в метод Выгрузить() параметр ОбходРезультатаЗапроса.ПоГруппировкамСИерархией. В тексте запроса должна быть секция ИТОГИ ПО с иерархией. Возвращённый объект будет иметь тип «ДеревоЗначений», его строки обходятся рекурсивно через коллекцию Строки.

Можно ли выгрузить в таблицу значений только часть колонок?

Напрямую методом Выгрузить() — нет, выгружаются все поля выборки. Правильное решение — оставить в секции ВЫБРАТЬ только нужные поля. Если текст запроса менять нельзя, после выгрузки удалите лишние колонки через ТЗ.Колонки.Удалить() или создайте копию методом Скопировать() с указанием списка колонок.

Что быстрее: Выгрузить() или обход через Выбрать()?

Для однократного последовательного чтения Выбрать() обычно экономичнее по памяти, так как не создаёт таблицу целиком. Выгрузить() оправдан, когда данные нужны повторно: поиск, сортировка, свёртка. Для небольших выборок (сотни–тысячи строк) разница практически незаметна, выбирайте по удобству дальнейшей обработки.

Как передать выгруженную таблицу значений на форму?

Создайте реквизит формы типа «ТаблицаЗначений» с нужными колонками и загрузите данные методом ЗначениеВРеквизитФормы(ТЗ, "ИмяРеквизита") на сервере. Для иерархических данных используйте реквизит типа «ДеревоЗначений». Прямое присваивание таблицы реквизиту формы не работает — требуется преобразование через ЗначениеВРеквизитФормы.

Итог

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

Выгрузка запроса в таблицу значений выполняется цепочкой Запрос.Выполнить().Выгрузить(). Задавайте псевдонимы полей через КАК, устанавливайте параметры до выполнения, выбирайте тип обхода осознанно: прямой для плоской таблицы, с иерархией — для дерева значений. Для больших однократно читаемых выборок предпочтительнее обход через Выбрать(), а при многократном поиске по таблице добавляйте индексы.