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

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

Как использовать вложенный запрос в 1С

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

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

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

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

Что такое вложенный запрос и когда он нужен

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

Использовать вложенный запрос оправдано, когда нужно сначала «свернуть» данные: например, получить суммы продаж по каждому контрагенту, а затем выбрать только тех, у кого сумма превышает порог. Одним запросом без вложенности это решается через ИМЕЮЩИЕ, но если после группировки нужно ещё и соединить результат с другими таблицами по агрегированному ключу — без вложенного запроса не обойтись.

Не стоит применять вложенность там, где задача решается проще: простую фильтрацию выполняет секция ГДЕ, а фильтрацию по итогам группировки — секция ИМЕЮЩИЕ. Каждый лишний уровень вложенности усложняет план выполнения запроса на СУБД и затрудняет отладку.

Синтаксис вложенного запроса в секции ИЗ

Базовая конструкция выглядит так: в секции ИЗ вместо имени таблицы указывается запрос в круглых скобках, после которого обязательно ставится псевдоним через ключевое слово КАК. Без псевдонима платформа выдаст синтаксическую ошибку, потому что к полям вложенной таблицы невозможно будет обратиться.

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

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

Вложенный запрос может участвовать в соединениях как обычная таблица: ЛЕВОЕ СОЕДИНЕНИЕ, ВНУТРЕННЕЕ СОЕДИНЕНИЕ и другие виды работают с ним без ограничений. Это основной приём для задачи «присоединить агрегированные данные к справочнику».

Вложенный запрос в условии: оператор В

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

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

При таком использовании вложенный запрос должен возвращать ровно одно поле — иначе платформа сообщит об ошибке несоответствия количества колонок. Рекомендуется добавлять РАЗЛИЧНЫЕ, чтобы набор значений не содержал дублей: это упрощает работу оптимизатора СУБД.

Альтернатива оператору В — соединение с вложенным запросом в секции ИЗ. Соединение предпочтительнее, когда из вложенного набора нужны не только ключи, но и дополнительные поля. Оператор В удобен именно для чистой фильтрации, когда данные вложенного запроса в результат не попадают.

Типовые сценарии применения

Получение последних значений на дату

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

Двойная группировка

Иногда нужно сгруппировать данные дважды: сначала посчитать суммы по документам, потом — среднее или максимум из этих сумм по контрагентам. Язык запросов 1С не позволяет вкладывать агрегатные функции друг в друга напрямую, поэтому первая группировка выполняется во вложенном запросе, а вторая — во внешнем. Это единственный корректный способ решить такую задачу одним запросом.

Фильтрация по результату соединения

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

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

Вложенный запрос или временная таблица: что выбрать

Пакетный запрос с временными таблицами — главная альтернатива вложенности. Результат промежуточного запроса помещается во временную таблицу командой ПОМЕСТИТЬ, а следующие запросы пакета обращаются к ней по имени. По сути это та же многоступенчатая обработка, но оформленная иначе.

Сравнение вариантов

Вложенный запрос

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

Временная таблица (ПОМЕСТИТЬ)

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

Секция ИМЕЮЩИЕ

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

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

Маршрут решения

Как выбрать действие

Нужно один раз сгруппировать или отфильтровать данные перед соединениемИспользуйте вложенный запрос в секции ИЗ
Нужно только отфильтровать по агрегатному условиюИспользуйте секцию ИМЕЮЩИЕ без вложенности
Промежуточный результат нужен в нескольких запросах или ступеней больше двухИспользуйте пакетный запрос с ПОМЕСТИТЬ во временную таблицу
Нужны последние значения периодического регистраСначала проверьте виртуальную таблицу СрезПоследних

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

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

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

Типичные ошибки
01
Нет псевдонима у вложенного запроса или у вычисляемого поля — синтаксическая ошибка при проверке текста
02
В условии В вложенный запрос возвращает несколько полей — ошибка несоответствия колонок
03
Условия отбора указаны только во внешнем запросе — СУБД обрабатывает лишние миллионы записей внутри
04
Три и более уровня вложенности — запрос невозможно отладить, лучше переписать на временные таблицы
05
Соединение по неиндексированным вычисляемым полям вложенного запроса — резкое падение скорости

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

Проверка результата и оптимизация

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

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

Для оценки скорости полезно замерять время выполнения на данных, близких к боевым по объёму. Запрос, который на пустой тестовой базе выполняется мгновенно, на реальных объёмах может работать минутами. Основные приёмы ускорения: фильтрация на нижнем уровне, отказ от лишних полей в секции ВЫБРАТЬ, использование РАЗЛИЧНЫЕ только там, где дубли действительно возможны.

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

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

Количество строк вложенного запроса
Норма

Соответствует ожидаемому набору после группировки или фильтра

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

Строк на порядки больше, чем нужно внешнему запросу — условия не перенесены внутрь

Итоговые суммы запроса
Норма

Совпадают с контрольным отчётом или оборотно-сальдовой ведомостью

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

Суммы завышены — вероятно задвоение из-за соединения без учёта дублей

Время выполнения на рабочем объёме данных
Норма

Запрос выполняется за время, приемлемое для сценария использования

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

Выполнение занимает минуты — нужна оптимизация или переход на временные таблицы

Частые вопросы о вложенных запросах в 1С

Можно ли вкладывать запрос в запрос несколько раз?

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

Нужно ли передавать параметры отдельно для вложенного запроса?

Нет. Параметры задаются один раз методом УстановитьПараметр() для всего запроса целиком и доступны на любом уровне вложенности. Один и тот же параметр можно использовать и во внешнем, и во вложенном запросе одновременно.

Что быстрее: вложенный запрос в условии В или соединение?

Однозначного ответа нет — зависит от СУБД, объёмов и индексов. На больших таблицах соединение с вложенным запросом в секции ИЗ нередко работает быстрее, чем оператор В. Если производительность критична, проверьте оба варианта замером на реальных данных.

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

Да. В конструкторе запросов на закладке «Таблицы и поля» можно добавить вложенный запрос как источник — для этого есть отдельная команда создания вложенного запроса. Псевдоним и состав полей настраиваются визуально, как для обычной таблицы.

Почему внешний запрос не видит поле из вложенного?

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

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

Когда промежуточный результат нужен в нескольких запросах, когда ступеней обработки больше двух, или когда запрос нужно отлаживать по частям. Временная таблица создаётся командой ПОМЕСТИТЬ в пакетном запросе, и каждый промежуточный результат можно вывести и проверить отдельно.

Итог

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

Вложенный запрос в 1С помещается в круглые скобки в секции ИЗ или в условии В и обязательно получает псевдоним через КАК. Условия отбора переносите на самый глубокий уровень, а при сложной многоступенчатой логике используйте временные таблицы пакетного запроса. Отладку и замеры выполняйте на копии базы.