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