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