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

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

Вложенный запрос в 1С: что это и как его использовать

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

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

Язык запросов 1С во многом повторяет логику SQL, поэтому вложенные запросы работают по тем же принципам: подзапрос заключается в круглые скобки и может располагаться в секции источников данных (FROM), в условиях отбора (WHERE / ГДЕ) и в некоторых других конструкциях. Результат подзапроса воспринимается внешним запросом как виртуальная таблица, которой нужно назначить псевдоним.

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

Где встречаются вложенные запросы в языке запросов 1С

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

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

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

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

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

ВЫБРАТЬ

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

Продажи.СуммаОборот КАК СуммаОборот

ПОМЕСТИТЬ ВТ_Продажи

ИЗ

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

;

ВЫБРАТЬ

Вложенные.Контрагент КАК Контрагент,

Вложенные.СуммаОборот КАК СуммаОборот

ИЗ

(ВЫБРАТЬ

ВТ.Контрагент КАК Контрагент,

СУММА(ВТ.СуммаОборот) КАК СуммаОборот

ИЗ

ВТ_Продажи КАК ВТ

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

ВТ.Контрагент) КАК Вложенные

ГДЕ

Вложенные.СуммаОборот > &Порог

Обратите внимание на обязательные элементы: круглые скобки вокруг подзапроса, псевдоним после КАК, именованные поля внутри подзапроса. Если поле вычисляемое (например, СУММА), ему обязательно нужно дать имя через КАК — иначе обратиться к нему снаружи не получится.

Вложенный запрос в условиях: операторы В и В ИЕРАРХИИ

Конструкция ГДЕ Поле В (подзапрос) удобна, когда список допустимых значений заранее неизвестен и вычисляется по данным базы. Классический пример — выбрать все документы по контрагентам, у которых есть задолженность.

ВЫБРАТЬ

Реализация.Ссылка КАК Документ,

Реализация.Контрагент КАК Контрагент

ИЗ

Документ.РеализацияТоваровУслуг КАК Реализация

ГДЕ

Реализация.Контрагент В

(ВЫБРАТЬ

Долги.Контрагент

ИЗ

РегистрНакопления.Взаиморасчеты.Остатки(&Период, ) КАК Долги

ГДЕ

Долги.СуммаОстаток > 0)

Оператор В ИЕРАРХИИ с подзапросом применяется к иерархическим справочникам: подзапрос возвращает группы, а внешний запрос отбирает элементы, входящие в эти группы на любом уровне вложенности. Это избавляет от необходимости программно обходить дерево справочника.

Для отрицания используется НЕ В. Здесь есть тонкость: такие запросы часто выполняются медленно на больших таблицах, потому что платформе приходится проверять отсутствие соответствия для каждой строки. Если данных много, сравните по скорости вариант с ЛЕВЫМ СОЕДИНЕНИЕМ и проверкой на NULL — нередко он работает быстрее.

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

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

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

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

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

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

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

Соединение вместо подзапроса в ГДЕ

Если подзапрос в условии В возвращает много строк, соединение с временной таблицей обычно работает быстрее и предсказуемее.

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

При переписывании вложенного запроса на временные таблицы не забывайте уничтожать ненужные таблицы оператором УНИЧТОЖИТЬ — в менеджере временных таблиц они занимают память сервера до конца выполнения пакета, а на больших выборках это заметно.
ПЗ
Практическое замечание

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

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

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

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

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

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

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

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

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

Строк больше (лишние дубли от соединения) или меньше (потеряны записи без соответствия)

Значения вычисляемых полей
Норма

Суммы и количества сходятся с данными регистра за тот же период

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

Значения завышены кратно — признак дублирования при соединении без нужной группировки

Скорость выполнения
Норма

Запрос выполняется за время, приемлемое для интерактивной работы

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

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

Производительность и ограничения

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

Есть и функциональные ограничения. Подзапрос в условии В возвращает только одно поле. В секции источников подзапрос нельзя использовать без псевдонима. Некоторые конструкции (например, раздел ИТОГИ внутри подзапроса) не поддерживаются — итоги допустимы только на верхнем уровне запроса.

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

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

Типичные ошибки
01
Подзапрос в условии В возвращает несколько полей — запрос не проходит проверку. В подзапросе для В должно быть ровно одно поле.
02
Отсутствует псевдоним у подзапроса в секции источников — платформа не сможет обратиться к его полям. Всегда добавляйте КАК ИмяПсевдонима.
03
Вычисляемое поле внутри подзапроса не именовано через КАК — к нему нельзя обратиться из внешнего запроса.
04
Использование НЕ В с подзапросом на больших таблицах без проверки скорости — запрос выполняется минутами. Проверьте вариант с левым соединением и условием ЕСТЬ NULL.
05
Дублирование строк из-за соединения с не сгруппированным подзапросом — суммы в отчёте завышены. Проверяйте кратность соединения контрольной выборкой.
06
Глубокая вложенность ради «одного красивого запроса» — текст невозможно отладить. Два-три уровня — разумный предел, дальше переходите на временные таблицы.

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

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

Итог

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

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

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

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

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

Можно ли использовать вложенный запрос в запросе СКД?

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

Почему запрос с подзапросом в условии В работает медленно?

Наиболее вероятные причины: подзапрос возвращает слишком много строк, не используются параметры виртуальных таблиц (период, отборы), или платформа не смогла построить эффективный план. Попробуйте поместить результат подзапроса во временную таблицу с индексом по полю соединения и заменить условие В на внутреннее соединение.

Сколько уровней вложенности допустимо?

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

Как посмотреть, что возвращает подзапрос, не запуская весь запрос?

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

Можно ли в подзапросе использовать итоги (ИТОГИ ПО)?

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