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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Как выбрать подход

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

Пример: последние документы по контрагентам

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

ВЫБРАТЬ

Заказы.Ссылка КАК Заказ,

Заказы.Контрагент КАК Контрагент,

Заказы.СуммаДокумента КАК Сумма

ИЗ

Документ.ЗаказКлиента КАК Заказы

ВНУТРЕННЕЕ СОЕДИНЕНИЕ (

ВЫБРАТЬ

ЗаказКлиента.Контрагент КАК Контрагент,

МАКСИМУМ(ЗаказКлиента.Дата) КАК МаксДата

ИЗ

Документ.ЗаказКлиента КАК ЗаказКлиента

ГДЕ

ЗаказКлиента.Проведен

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

ЗаказКлиента.Контрагент

) КАК Последние

ПО Заказы.Контрагент = Последние.Контрагент

И Заказы.Дата = Последние.МаксДата

ГДЕ

Заказы.Проведен

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

Как построить вложенный запрос в конструкторе
  1. 1
    Создайте основной запрос и откройте конструктор запроса
  2. 2
    На закладке «Таблицы и поля» нажмите «Добавить» и выберите «Вложенный запрос»
  3. 3
    Сконструируйте внутренний запрос: источник, поля, группировка, условия
  4. 4
    Задайте псевдоним вложенной таблицы
  5. 5
    Выберите нужные поля внешнего запроса и настройте соединения
  6. 6
    Нажмите «Запрос» → «Выполнить» и проверьте результат на тестовых данных

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

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

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

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

Сравнение подходов

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

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

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

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

ИМЕЮЩИЕ

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

Два отдельных запроса из кода

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

Типичные ошибки и ограничения

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

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

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

Типичные ошибки
01
Нет псевдонима у вложенного запроса — поля недоступны, запрос не сохраняется в конструкторе
02
Условия отбора только во внешнем запросе — внутренняя выборка читает лишние миллионы строк
03
Вложенность 3+ уровня — запрос невозможно отладить, СУБД строит плохой план
04
Соединение по дате без учёта момента времени — дубли строк при нескольких документах в одну секунду
05
Использование вложенного запроса вместо ИМЕЮЩИЕ — усложнение без выигрыша

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

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

Для оценки скорости замерьте время выполнения на реальном объёме данных, а не на демо-базе. Если запрос работает медленно, сравните его с вариантом на временной таблице с индексированием полей соединения — во многих случаях это даёт заметный прирост без изменения логики.

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

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

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

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

Соответствует числу групп (например, контрагентов)

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

Строк больше — дубли из-за неоднозначного соединения

Условия отбора
Норма

Период и проведённость заданы и во вложенном, и во внешнем запросе

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

Фильтр только снаружи — внутренняя выборка читает всё

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

Запрос выполняется за приемлемое время на реальном объёме

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

Многократный рост времени — переходите на временные таблицы

Псевдонимы полей
Норма

Все поля адресуются через псевдонимы таблиц

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

Ошибка неоднозначности поля в конструкторе

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

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

Можно ли использовать вложенный запрос в динамическом списке?

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

Чем вложенный запрос отличается от ИМЕЮЩИЕ?

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

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

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

Почему запрос с вложенной выборкой работает медленно?

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

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

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

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

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

Итог

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

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