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