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