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