При разработке сложных отчетов или механизмов обработки данных в 1С часто возникает задача получить значение из другой таблицы в зависимости от типа основания. Естественным желанием разработчика является попытка вставить полноценный вложенный запрос прямо внутрь конструкции ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ. Однако, при попытке реализации такого подхода, платформа выдает ошибку синтаксиса. Давайте разберемся, почему так происходит и как правильно решить эту задачу.
Язык запросов 1С:Предприятия — это декларативный язык, который транслируется в SQL-запросы к СУБД. Конструкция ВЫБОР КОГДА является выражением, которое должно возвращать конкретное скалярное значение. Вложенный запрос ВЫБРАТЬ ... ИЗ ..., в свою очередь, является самостоятельной выборкой данных. Архитектурно язык запросов 1С не поддерживает размещение целых табличных выражений внутри операторов выбора. В ветках ТОГДА и ИНАЧЕ допускается использовать только поля, параметры или простые вычисления, но не полноценные ВЫБРАТЬ конструкции.
Наиболее эффективным и «правильным» с точки зрения производительности способом получения данных из связанных таблиц или табличных частей является ЛЕВОЕ СОЕДИНЕНИЕ. Давайте разберем по шагам, как это реализовать.
Представим, что у нас есть задача: получить контактное лицо из табличной части документа Событие, если основанием является именно этот документ. Вместо того чтобы пытаться выполнить подзапрос внутри условия, мы сделаем следующее:
ВЫБОР КОГДА для выбора уже готового поля, полученного через соединение.Рассмотрим пример реализации такого запроса:
ВЫБРАТЬ
ЗадачаСотрудника.Ссылка КАК Задача,
ВЫБОР
КОГДА ЗадачаСотрудника.Основание ССЫЛКА Справочник.Контрагенты
ТОГДА ЗадачаСотрудника.Основание
КОГДА ЗадачаСотрудника.Основание ССЫЛКА Документ.Событие
ТОГДА СобытиеУчастники.Контакт
ИНАЧЕ ЗадачаСотрудника.Основание.Контрагент
КОНЕЦ КАК Результат
ИЗ
Документ.ЗадачаСотрудника КАК ЗадачаСотрудника
ЛЕВОЕ СОЕДИНЕНИЕ Документ.Событие.Участники КАК СобытиеУчастники
ПО ЗадачаСотрудника.Основание = СобытиеУчастники.Ссылка
И СобытиеУчастники.НомерСтроки = 1
Проанализируем преимущества данного подхода:
LEFT JOIN по индексированным полям (в данном случае Ссылка табличной части). Это значительно быстрее, чем любые попытки эмулировать подзапросы.СобытиеУчастники.НомерСтроки = 1 гарантирует, что мы получим строго одну строку из табличной части, что решает проблему «лишних данных», возникающую при простом соединении.Если логика получения данных из табличной части документа очень сложная (например, нужно отфильтровать участников по нескольким критериям, а не просто взять первого), рекомендуем использовать пакет запросов. В этом случае работа разбивается на этапы:
ВРЕМЕННУЮ ТАБЛИЦУ.ПЕРВЫЕ 1 или ГРУППИРОВАТЬ ПО.ЛЕВОЕ СОЕДИНЕНИЕ уже с этой временной таблицей.Такой подход делает код «чистым», позволяет легко отлаживать каждый этап выборки данных и избавляет от громоздких конструкций внутри одного единственного запроса. Не стоит бояться соединений — при грамотном использовании индексов они являются основой быстродействия платформы 1С:Предприятие. При работе со сложными пакетами для корректного освобождения памяти можно использовать инструмент для оптимизации временных таблиц в пакетных запросах.