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