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