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