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

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

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

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

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

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

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

Минимальный пример выгрузки результата запроса в таблицу значений состоит из четырёх строк. Создайте объект Запрос, присвойте текст, выполните его и вызовите Выгрузить у полученного результата.

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

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

После выполнения этого кода переменная ТаблицаТоваров содержит объект типа ТаблицаЗначений. Колонки таблицы соответствуют полям выборки запроса, а имена колонок совпадают с псевдонимами полей, заданными через КАК в тексте запроса.

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

bsl
Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(Период));
Запрос.УстановитьПараметр("Склад", СкладОтбора);
РезультатЗапроса = Запрос.Выполнить();
ТаблицаДанных = РезультатЗапроса.Выгрузить();

Разница между Выгрузить и Выбрать

Метод Выбрать возвращает выборку из результата запроса — последовательный курсор для построчного чтения. Метод Выгрузить возвращает готовую таблицу значений целиком в памяти. Выбор зависит от того, что вы будете делать с данными дальше.

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

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

Выгрузить()

Вся таблица в памяти, доступны поиск, сортировка, свёртка и изменение строк. Подходит для небольших и средних результатов и для передачи данных между процедурами.

Выбрать()

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

Выгрузить с итогами

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

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

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

Метод Выгрузить принимает необязательный параметр типа ОбходРезультатаЗапроса. От него зависит структура полученной таблицы, и непонимание этого момента — источник большинства вопросов «почему в таблице не все строки».

По умолчанию используется обход ПоГруппировкам: в таблицу попадают строки верхнего уровня иерархии результата. Если в запросе есть итоги (конструкция ИТОГИ ПО), без параметра вы получите только итоговые строки, а детальные записи окажутся вложены в них. Если итогов в запросе нет, поведение фактически совпадает с прямым обходом.

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

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

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

При обходе ПоГруппировкамСИерархией таблица значений получает вложенную структуру: у каждой строки есть коллекция Строки, содержащая подчинённые записи. Это удобно для вывода дерева на форму, но для плоской обработки обычно нужен именно Прямой обход.

Типы колонок и их особенности

При выгрузке таблица значений наследует типы колонок из результата запроса. Если поле запроса может содержать значения разных типов (например, составной тип или значение NULL из левого соединения), колонка получит составной тип. Это влияет на сортировку и сравнение: смешанные типы сравниваются по внутренним правилам платформы, что иногда даёт неожиданный порядок.

Значения NULL из запроса превращаются в значение NULL в ячейке таблицы значений. При последующей обработке проверяйте такие ячейки через ЗначениеЗаполнено или сравнение с NULL, иначе арифметические операции с NULL приведут к ошибке. Альтернатива — обработать NULL ещё в запросе функцией ЕСТЬNULL.

bsl
// В тексте запроса замените NULL на значение по умолчанию:
// ВЫБРАТЬ ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток ...

// Проверка при обходе таблицы
Для Каждого СтрокаТЗ Из ТаблицаДанных Цикл
    Если СтрокаТЗ.Остаток = NULL Тогда
        Продолжить;
    КонецЕсли;
КонецЦикла;

Если структура таблицы должна быть строго определена заранее (например, для передачи в универсальную процедуру), иногда удобнее создать таблицу значений вручную с явными типами колонок и заполнять её из выборки. Это длиннее, но даёт полный контроль над типами и порядком колонок.

Практические приёмы работы с выгруженной таблицей

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

bsl
// Поиск строк по условию
Отбор = Новый Структура("Товар", НужныйТовар);
НайденныеСтроки = ТаблицаДанных.НайтиСтроки(Отбор);

// Сортировка
ТаблицаДанных.Сортировать("Код Возр");

// Свёртка: группировка по колонке Товар, суммирование Остатка
ТаблицаДанных.Свернуть("Товар", "Остаток");

// Добавление вычисляемой колонки
ТаблицаДанных.Колонки.Добавить("СуммаСНДС");
Для Каждого СтрокаТЗ Из ТаблицаДанных Цикл
    СтрокаТЗ.СуммаСНДС = СтрокаТЗ.Сумма * 1.2;
КонецЦикла;

Учтите, что Свернуть изменяет таблицу «на месте» и необратимо удаляет детальные строки. Если исходные данные ещё понадобятся, предварительно сделайте копию методом Скопировать. Аналогично Сортировать меняет порядок строк в самой таблице, а не возвращает новую.

Для передачи таблицы на управляемую форму используется реквизит формы типа ТаблицаЗначений и метод Загрузить у объекта ДанныеФормыКоллекция, либо преобразование через ЗначениеВДанныеФормы. Напрямую присвоить таблицу значений реквизиту формы нельзя — это отдельная тема, но выгрузка из запроса является типичным первым шагом такой задачи.

Типовой порядок действий
  1. 1
    Создайте объект Запрос и задайте текст с понятными псевдонимами полей
  2. 2
    Установите все параметры запроса через УстановитьПараметр
  3. 3
    Выполните запрос и проверьте результат методом Пустой()
  4. 4
    Вызовите Выгрузить с нужным типом обхода (обычно Прямой)
  5. 5
    Проверьте количество строк и типы колонок полученной таблицы
  6. 6
    Выполните дальнейшую обработку: поиск, сортировку, свёртку или передачу в другую процедуру

Типичные ошибки и как их избежать

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

Типичные ошибки
01
Вызов Выгрузить() без параметра при наличии ИТОГИ ПО в запросе — в таблице оказываются только итоговые строки, детальные записи теряются из виду
02
Обращение к колонке по имени поля из запроса без псевдонима КАК — фактическое имя колонки может отличаться, лучше всегда задавать псевдонимы явно
03
Выгрузка огромного результата в память ради простого обхода — лишний расход памяти, в таких случаях нужен метод Выбрать
04
Игнорирование значений NULL в ячейках — арифметика или сравнение с NULL приводит к ошибкам выполнения
05
Использование Свернуть без предварительной копии — исходные детальные данные теряются безвозвратно

Отдельно стоит упомянуть имена колонок. Если в запросе поле указано без псевдонима, имя колонки формируется платформой автоматически и может не совпадать с тем, что вы ожидаете (например, при выборе поля через точку). Правило простое: каждому полю выборки давайте явный псевдоним через КАК и обращайтесь к колонкам таблицы именно по этим псевдонимам.

Ещё одна ситуация — выгрузка пустого результата. Метод Выгрузить корректно возвращает таблицу значений с нулём строк, но с заданной структурой колонок. Поэтому проверять наличие данных лучше не через Пустой() результата запроса, а через ТаблицаДанных.Количество(), если дальнейшая логика работает именно с таблицей.

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

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

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

ТаблицаДанных.Количество() соответствует ожидаемому числу записей

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

Строк меньше, чем в данных — вероятно, использован обход по группировкам при наличии ИТОГИ

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

Колонки доступны по псевдонимам, заданным через КАК в запросе

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

Ошибка «Поле не найдено» — имя колонки не совпадает с ожидаемым

Значения ячеек
Норма

Числовые поля содержат числа, ссылочные — ссылки ожидаемого типа

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

В ячейках NULL или значения неожиданного типа — проверьте соединения и ЕСТЬNULL в запросе

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

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

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

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

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

Частые вопросы

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

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

Чем отличается таблица значений от дерева значений при выгрузке запроса?

Метод Выгрузить у результата запроса всегда возвращает таблицу значений. Чтобы получить дерево значений с иерархией по группировкам, используйте у результата запроса метод Выгрузить с обходом ПоГруппировкамСИерархией — у строк такой таблицы появляется коллекция Строки, что фактически даёт древовидную структуру. Отдельный тип ДеревоЗначений обычно создаётся вручную или получается через ЗначениеВДерево.

Почему после выгрузки сортировка по числовой колонке работает странно?

Почти всегда причина в составном типе колонки: если в поле запроса могли попасть значения разных типов или NULL, колонка получает составной тип, и сравнение идёт не как чисто числовое. Проверьте тип колонки, замените NULL через ЕСТЬNULL в запросе и при необходимости приведите поле к нужному типу функцией ВЫРАЗИТЬ в тексте запроса.

Как выгрузить результат пакетного запроса из нескольких выборок?

Метод ВыполнитьПакет возвращает массив результатов запросов. К каждому элементу массива применяется Выгрузить отдельно: Таблица1 = Результаты[0].Выгрузить(). Учтите, что временные таблицы в пакете тоже занимают позиции в массиве, поэтому индексы полезных результатов нужно считать с учётом всех запросов пакета.

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

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

Что быстрее: обход выборки или обход выгруженной таблицы значений?

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

Итог

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

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