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