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