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

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

Вложенный запрос в 1С: когда используется и как его применять

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

Вложенный запрос в языке запросов 1С — это запрос, помещённый в круглые скобки внутри секции ИЗ (FROM) другого запроса. Внешний запрос обращается к нему как к обычной таблице-источнику: присваивает ему псевдоним и использует его поля в соединениях, условиях и группировках. Такая конструкция позволяет выполнить двухступенчатую обработку данных одним обращением к СУБД.

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

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

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

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

ВЫБРАТЬ

Продажи.Контрагент,

Продажи.СуммаПродаж

ИЗ

(ВЫБРАТЬ

ПродажиОбороты.Контрагент КАК Контрагент,

СУММА(ПродажиОбороты.СуммаОборот) КАК СуммаПродаж

ИЗ

РегистрНакопления.Продажи.Обороты КАК ПродажиОбороты

СГРУППИРОВАТЬ ПО

ПродажиОбороты.Контрагент) КАК Продажи

ГДЕ

Продажи.СуммаПродаж > 100000

В этом примере внутренний запрос агрегирует обороты, а внешний отбирает только крупных клиентов. Условие по сумме нельзя было бы поставить в секцию ГДЕ внутреннего запроса напрямую — агрегатные функции фильтруются через ИМЕЮЩИЕ либо через внешний уровень.

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

Основные сценарии, когда вложенный запрос оправдан

Предварительная группировка перед соединением

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

Фильтрация по агрегированным значениям

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

Получение «последних» или «максимальных» значений

Классическая задача: найти последнюю цену, последний документ, максимальную дату по каждому объекту. Внутренний запрос вычисляет МАКСИМУМ(Дата) в группировке по объекту, внешний соединяет этот результат с исходной таблицей по составному ключу «объект + дата», чтобы подтянуть остальные поля строки.

Двойная агрегация

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

Нужна группировка до соединенияДа

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

Уровней вложенности2 и более

Признак того, что пора переходить на пакетный запрос с временными таблицами

Запрос нужно отлаживать по шагамДа

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

Одноразовая простая выборкаДа

Один уровень вложенности читается нормально, усложнять не нужно

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

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

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

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

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

Подходит для одного уровня вложенности и короткой логики. Компактно, всё в одном тексте. Ограничение: плохо отлаживается, тяжело читается при усложнении.

Временная таблица

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

ИМЕЮЩИЕ (HAVING)

Подходит для фильтрации по агрегатам без дополнительных уровней. Самый простой вариант, если соединение с агрегатом не требуется.

Практическое правило: если вложенность одна и внутренний запрос короткий (до 10–15 строк), оставляйте вложенный запрос. Если уровней два и больше, либо промежуточный результат нужен в нескольких местах — переходите на временные таблицы.

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

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

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

Производительность: что важно учитывать

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

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

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

Пошаговый порядок написания вложенного запроса

Надёжная методика — строить запрос изнутри наружу, проверяя каждый уровень отдельно. Это особенно удобно в консоли запросов или через конструктор.

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

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

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

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

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

Совпадает с ожидаемой размерностью (например, одна строка на контрагента)

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

Строк больше — значит, соединение дублирует данные из-за недостаточной группировки

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

Сходятся с контрольным отчётом по тем же данным

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

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

Время выполнения
Норма

Запрос отрабатывает за приемлемое время на объёме, близком к рабочему

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

Время растёт нелинейно с объёмом — проверьте индексы и отборы во внутреннем запросе

Типичные ошибки при работе с вложенными запросами

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

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

Отдельно отметим ошибку с ИТОГИ: итоги по группировкам строятся уже по результату внешнего запроса, поэтому если внутренний запрос подготовил данные неверно, итоги «честно» просуммируют ошибку. Всегда сверяйте генеральные итоги с независимым источником.

Удобный приём при отладке: временно замените вложенный запрос на временную таблицу, выгрузите её содержимое в таблицу значений и посмотрите глазами. Когда логика проверена, можно вернуть конструкцию во вложенный вид, если важна компактность текста.
ПЗ
Практическое замечание

Ограничения и частные случаи

Вложенный запрос не может содержать секции ИТОГИ — итоги допустимы только на верхнем уровне запроса. Также внутри вложенного запроса нельзя использовать конструкцию УПОРЯДОЧИТЬ ПО с ожиданием, что порядок сохранится во внешнем результате: порядок строк гарантирует только упорядочивание внешнего запроса.

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

В иерархических запросах (ИТОГИ ПО … ИЕРАРХИЯ) вложенность в секции ИЗ работает как обычно, но сама иерархия строится внешним запросом — это ещё один аргумент держать внутренний уровень максимально простым.

Итог

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

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

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

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

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

Можно ли использовать вложенный запрос в секции ГДЕ?

Да, в условиях допустимы подзапросы в конструкциях вида В (ВЫБРАТЬ …) — например, отобрать документы, чьи контрагенты входят в выборку из другого запроса. Однако для массовых отборов эффективнее соединение с вложенным запросом или временной таблицей в секции ИЗ.

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

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

Есть ли ограничение на глубину вложенности?

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

Как отладить вложенный запрос, если он возвращает не то?

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

Работают ли вложенные запросы в СКД?

Да, набор данных типа «Запрос» в схеме компоновки данных поддерживает вложенные запросы в полном объёме. Но учитывайте, что СКД сама модифицирует текст запроса при применении отборов и группировок, поэтому избыточно сложные вложенные конструкции в СКД лучше заменять временными таблицами или наборами-объединениями.