Как в запросе динамического списка вывести значение по умолчанию при отсутствии связанных записей в регистре?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интерфейсов на управляемых формах часто возникает задача отобразить в динамическом списке справочника признак наличия связанных записей в регистре сведений. Например, если для элемента справочника есть соответствующие записи в регистре, требуется вывести «Да», а если записей нет — «Нет».

Однако при использовании левого соединения с вложенным запросом разработчики часто сталкиваются с ситуацией, когда вместо ожидаемого значения «Нет» в ячейке отображается пустота. Разберем по шагам, почему возникает такое поведение, как исправить логику запроса и как оптимизировать производительность динамического списка.

Анализ проблемы: почему в ячейке отображается пустота

Рассмотрим типичную ошибку при построении текста запроса:


ВЫБРАТЬ
    СправочникПричиныПростояОборудования.Код,
    СправочникПричиныПростояОборудования.Наименование,
    ВложенныйЗапрос.Причина,
    ВложенныйЗапрос.ПричинаСсылка
ИЗ
    Справочник.ПричиныПростояОборудования КАК СправочникПричиныПростояОборудования
    ЛЕВОЕ СОЕДИНЕНИЕ (
        ВЫБРАТЬ
            ВЫБОР 
                КОГДА КОЛИЧЕСТВО(ВходимостьВКТГ.Причина) > 0 ТОГДА "Да"
                ИНАЧЕ "Нет"
            КОНЕЦ КАК Причина,
            ВходимостьВКТГ.Причина КАК ПричинаСсылка
        ИЗ
            РегистрСведений.ВходимостьВКТГ КАК ВходимостьВКТГ
        СГРУППИРОВАТЬ ПО
            ВходимостьВКТГ.Причина
    ) КАК ВложенныйЗапрос
    ПО СправочникПричиныПростояОборудования.Ссылка = ВложенныйЗапрос.ПричинаСсылка

Выясним причину, почему ветка ИНАЧЕ "Нет" внутри вложенного запроса не срабатывает:

  1. Вложенный запрос выбирает данные только из таблицы регистра сведений. Если по какому-то элементу справочника записей в регистре нет вовсе, то такой элемент даже не попадет в выборку подзапроса.
  2. При выполнении операции ЛЕВОЕ СОЕДИНЕНИЕ для строк справочника, не имеющих соответствия во вложенной таблице, все поля этой вложенной таблицы получают специальное значение NULL.
  3. В результате поле ВложенныйЗапрос.Причина возвращает не строку «Нет», а значение NULL, которое на форме отображается как пустая ячейка.

Кроме того, при формировании текста запроса в программном коде 1С важно помнить о синтаксических правилах:

  1. Экранирование строковых литералов: при присвоении текста запроса строковой переменной (Список.ТекстЗапроса = "...") внутренние кавычки обязательно должны быть двойными (например, ""Да""). Пропуск экранирования приводит к ошибке компиляции запроса.
  2. Сигнатура функции ЕСТЬNULL: данная функция принимает строго два параметра — ЕСТЬNULL(ПроверяемоеПоле, ЗначениеЗамены). Попытка передать три параметра (по аналогии с условным оператором) вызовет синтаксическую ошибку платформы.
  3. Лишние разыменования: обращение к ссылке через точку (например, ВходимостьВКТГ.Причина.Ссылка) порождает в СУБД дополнительное неявное левое соединение, что создает лишнюю нагрузку. Достаточно использовать само поле ВходимостьВКТГ.Причина.

Вариант 1. Обработка условия в основном запросе (базовое решение)

Чтобы корректно обработать отсутствие данных, перенесем проверку на верхний уровень запроса. Проверим результат соединения с помощью конструкции ВЫБОР и функции ЕСТЬNULL.

Посмотрим на пример кода, формирующего текст запроса динамического списка:


Список.ПроизвольныйЗапрос = Истина;
Список.ТекстЗапроса = 
    "ВЫБРАТЬ
    |    СправочникПричиныПростояОборудования.Код КАК Код,
    |    СправочникПричиныПростояОборудования.Наименование КАК Наименование,
    |    ВЫБОР
    |        КОГДА ЕСТЬNULL(ВложенныйЗапрос.КоличествоЗаписей, 0) > 0 ТОГДА ""Да""
    |        ИНАЧЕ ""Нет""
    |    КОНЕЦ КАК ЕстьВхождение,
    |    СправочникПричиныПростояОборудования.Ссылка КАК Ссылка
    |ИЗ
    |    Справочник.ПричиныПростояОборудования КАК СправочникПричиныПростояОборудования
    |    ЛЕВОЕ СОЕДИНЕНИЕ (
    |        ВЫБРАТЬ
    |            КОЛИЧЕСТВО(ВходимостьВКТГ.Причина) КАК КоличествоЗаписей,
    |            ВходимостьВКТГ.Причина КАК ПричинаСсылка
    |        ИЗ
    |            РегистрСведений.ВходимостьВКТГ КАК ВходимостьВКТГ
    |        СГРУППИРОВАТЬ ПО
    |            ВходимостьВКТГ.Причина
    |    ) КАК ВложенныйЗапрос
    |    ПО СправочникПричиныПростояОборудования.Ссылка = ВложенныйЗапрос.ПричинаСсылка";

В этом случае при отсутствии совпадения во вложенном запросе ЕСТЬNULL подставляет число 0, условие > 0 не выполняется, и запрос гарантированно возвращает строку «Нет».

Вариант 2. Оптимизированный запрос с использованием ключевого слова РАЗЛИЧНЫЕ

Если задача заключается только в проверке факта наличия записей в регистре, подсчет их точного количества с помощью КОЛИЧЕСТВО(...) и СГРУППИРОВАТЬ ПО является избыточной операцией для СУБД. Оптимизируем запрос, используя конструкцию РАЗЛИЧНЫЕ и проверку поля на NULL.

Кроме того, с точки зрения стандартов разработки 1С строковые поля «Да» / «Нет» менее эффективны для поиска, сортировки и отборов, чем стандартный булев тип (Истина / Ложь).

Разберем оптимальную структуру запроса:


Список.ПроизвольныйЗапрос = Истина;
Список.ТекстЗапроса = 
    "ВЫБРАТЬ
    |    СправочникПричиныПростояОборудования.Ссылка КАК Ссылка,
    |    СправочникПричиныПростояОборудования.Код КАК Код,
    |    СправочникПричиныПростояОборудования.Наименование КАК Наименование,
    |    ВЫБОР
    |        КОГДА ВложенныйЗапрос.Причина ЕСТЬ NULL ТОГДА ЛОЖЬ
    |        ИНАЧЕ ИСТИНА
    |    КОНЕЦ КАК ВходитВКТГ
    |ИЗ
    |    Справочник.ПричиныПростояОборудования КАК СправочникПричиныПростояОборудования
    |    ЛЕВОЕ СОЕДИНЕНИЕ (
    |        ВЫБРАТЬ РАЗЛИЧНЫЕ
    |            ВходимостьВКТГ.Причина КАК Причина
    |        ИЗ
    |            РегистрСведений.ВходимостьВКТГ КАК ВходимостьВКТГ
    |    ) КАК ВложенныйЗапрос
    |    ПО СправочникПричиныПростояОборудования.Ссылка = ВложенныйЗапрос.Причина";

Чтобы колонка отображалась в привычном для пользователя виде, настроим элемент формы:

  1. Добавим поле ВходитВКТГ в элементы таблицы формы.
  2. В свойствах созданной колонки установим свойство Формат: БЛ=Нет; БИ=Да (либо включим отображение в виде флажка).

Такой подход обеспечивает корректное отображение информации, снижает объем передаваемых данных между сервером и клиентом, а также позволяет пользователям настраивать стандартную фильтрацию по булеву признаку.

Влияние на производительность и альтернативное решение

Проанализируем влияние вложенных запросов на динамические списки:

  1. Полное сканирование (Full Scan): Вложенный запрос по регистру сведений при динамическом считывании порций данных выполняется целиком. При больших объемах данных в регистре это может приводить к существенным задержкам при открытии формы и прокрутке списка.
  2. Архитектурная альтернатива (денормализация): Если таблица регистра содержит сотни тысяч записей, наиболее производительным решением будет добавление в справочник реквизита ВходитВКТГ булева типа. Значение этого реквизита актуализируется в обработчиках записи регистра. В этом случае динамический список будет считывать данные напрямую из таблицы справочника по первичному индексу без использования соединений.
← На главную