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