После обновления платформы 1С:Предприятие до версий 8.3.15, 8.3.16 (и выше), а также при повышении режима совместимости конфигурации «Бухгалтерия предприятия 3.0» (начиная с релизов 3.0.75), разработчики часто сталкиваются с крайне неприятной проблемой. Отчеты, построенные на Системе компоновки данных (СКД) и выводящие данные по дополнительным реквизитам, внезапно перестают работать. При установке множественного отбора (например, одновременно по двум доп. реквизитам «Цвет» и «Размер») отчет выводит абсолютно пустую страницу. При этом в обычной консоли запросов тот же самый запрос с аналогичными параметрами отрабатывает быстро и возвращает корректные строки.
В этой статье мы подробно проанализируем ситуацию, выясним глубинную причину такого поведения оптимизатора СКД и разберем по шагам три практических способа решения этой проблемы.
Рассмотрим структуру запроса, который традиционно использовался разработчиками для «разворачивания» табличной части дополнительных реквизитов в плоскую таблицу с колонками. Обычно это пакет запросов или один сложный запрос с конструкцией ОБЪЕДИНИТЬ ВСЕ (UNION ALL), помещающий данные во временную таблицу:
ВЫБРАТЬ
НоменклатураДополнительныеРеквизиты.Ссылка КАК Номенклатура,
НоменклатураДополнительныеРеквизиты.Значение КАК Цвет,
NULL КАК Размер
ПОМЕСТИТЬ ВТ_Свойства
ИЗ
Справочник.Номенклатура.ДополнительныеРеквизиты КАК НоменклатураДополнительныеРеквизиты
ГДЕ
НоменклатураДополнительныеРеквизиты.Свойство.Наименование = &НаименованиеЦвет
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
НоменклатураДополнительныеРеквизиты.Ссылка,
NULL,
НоменклатураДополнительныеРеквизиты.Значение
ИЗ
Справочник.Номенклатура.ДополнительныеРеквизиты КАК НоменклатураДополнительныеРеквизиты
ГДЕ
НоменклатураДополнительныеРеквизиты.Свойство.Наименование = &НаименованиеРазмер
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_Свойства.Номенклатура КАК Номенклатура,
МАКСИМУМ(ВТ_Свойства.Цвет) КАК Цвет,
МАКСИМУМ(ВТ_Свойства.Размер) КАК Размер
ПОМЕСТИТЬ ВТ_Итог
ИЗ
ВТ_Свойства КАК ВТ_Свойства
СГРУППИРОВАТЬ ПО
ВТ_Свойства.Номенклатура
В этой схеме в первой ветке объединения выбирается свойство «Цвет», а поле «Размер» жестко заполняется значением NULL. Во второй ветке — наоборот: выбирается «Размер», а поле «Цвет» принудительно устанавливается в NULL. Затем происходит группировка по номенклатуре с получением максимума по колонкам свойств, что позволяет «схлопнуть» строки и избавиться от лишних NULL.
Эта схема отлично работала годами на старых версиях платформы (например, 8.3.13 и ниже). Однако, начиная с версии платформы 8.3.15, разработчики 1С существенно переработали и оптимизировали поведение компоновщика макета СКД. Теперь при включенном свойстве «Автозаполнение» СКД пытается максимально оптимизировать SQL-запрос, транслируя (или «проталкивая») пользовательские отборы внутрь всех вложенных запросов и веток объединения.
Проанализируем, что происходит, когда пользователь устанавливает в настройках отчета множественный отбор:
Цвет = "Красный" И Размер = "XL"
Новый оптимизатор СКД берет эти два условия и накладывает их на каждую ветку объединения внутри временной таблицы ВТ_Свойства. В итоге СУБД получает следующий модифицированный запрос:
ГДЕ (Значение = "Красный") И (NULL = "XL"). Поскольку сравнение NULL с любым конкретным значением всегда возвращает Ложь (или UNKNOWN), эта ветка не возвращает ни одной строки.ГДЕ (NULL = "Красный") И (Значение = "XL"). Ситуация аналогична: из-за сравнения NULL = "Красный" ветка возвращает ровно 0 строк.В результате временная таблица ВТ_Свойства оказывается абсолютно пустой. Последующая группировка также возвращает пустой результат, и пользователь видит белый экран в отчете. При этом, если установить отбор только по одному свойству (например, только по цвету), отчет сработает, так как условие по размеру не будет транслироваться в ветки запроса.
Теперь, когда мы досконально понимаем физику процесса, рассмотрим три варианта решения этой проблемы.
Написание сложных запросов с конструкциями UNION ALL для получения дополнительных реквизитов — это устаревший подход, который часто приводит к избыточной нагрузке на СУБД. В СКД встроен мощный, быстрый и оптимизированный механизм для автоматического получения дополнительных реквизитов (характеристик), созданных в режиме «1С:Предприятие» через БСП.
Рассмотрим подробнее процесс настройки механизма характеристик в СКД:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Номенклатура,
Номенклатура.НоменклатурнаяГруппа КАК НоменклатурнаяГруппа
ИЗ
Справочник.Номенклатура КАК Номенклатура
Номенклатура (объект, к которому привязаны свойства).ДополнительныеРеквизитыИСведения.Ссылка.Наименование.ТипЗначения.Справочник.Номенклатура.ДополнительныеРеквизиты.Ссылка (ссылка на элемент номенклатуры).Свойство.Значение.После этой несложной настройки платформа сама динамически расширит доступные поля объекта Номенклатура в дереве СКД. Пользователь сможет выбирать любые дополнительные реквизиты (Цвет, Размер, ГОСТ) прямо через точку от номенклатуры как в полях выбора, так и в настройках отборов. При этом СКД самостоятельно сгенерирует максимально эффективный SQL-запрос к СУБД, избежав проблемы пустых результатов при множественном отборе.
Если по каким-то причинам использование механизма характеристик невозможно (например, структура данных требует жесткого вывода определенных реквизитов строго в отдельные колонки отчета по умолчанию), мы можем полностью отказаться от конструкции UNION ALL в пользу последовательных левых соединений.
Проанализируем этот вариант. Вместо объединения строк по вертикали, мы сразу собираем их по горизонтали, соединяя таблицу номенклатуры саму с собой по ее табличной части дополнительных реквизитов:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Номенклатура,
Номенклатура.НоменклатурнаяГруппа КАК НоменклатурнаяГруппа,
ЕСТЬNULL(ДопЦвет.Значение, ЗНАЧЕНИЕ(Справочник.ЗначенияСвойствОбъектов.ПустаяСсылка)) КАК Цвет,
ЕСТЬNULL(ДопРазмер.Значение, ЗНАЧЕНИЕ(Справочник.ЗначенияСвойствОбъектов.ПустаяСсылка)) КАК Размер
ПОМЕСТИТЬ ВТ_ИтоговыеДанные
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопЦвет
ПО Номенклатура.Ссылка = ДопЦвет.Ссылка
И ДопЦвет.Свойство.Наименование = &НаименованиеЦвет
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопРазмер
ПО Номенклатура.Ссылка = ДопРазмер.Ссылка
И ДопРазмер.Свойство.Наименование = &НаименованиеРазмер
При такой структуре запроса для каждой номенклатуры формируется одна единственная строка, где одновременно заполнены и цвет, и размер (если они заданы в базе данных). В этом случае, когда пользователь накладывает множественный отбор СКД ГДЕ Цвет = &Цвет И Размер = &Размер, оптимизатор корректно отрабатывает условия, так как в результирующей строке больше нет искусственных полей со значением NULL, исключающих друг друга.
Если ваш отчет построен на очень сложном запросе, переписывать который на левые соединения трудозатратно, существует способ принудительно запретить СКД оптимизировать условия и «проталкивать» отборы во все ветки объединения.
Разберем этот метод по шагам:
{} прямо в тексте запроса.Модифицируем текст исходного запроса с использованием расширения языка запросов СКД:
ВЫБРАТЬ
НоменклатураДополнительныеРеквизиты.Ссылка КАК Номенклатура,
НоменклатураДополнительныеРеквизиты.Значение КАК Цвет,
NULL КАК Размер
{ВЫБРАТЬ Номенклатура.*, Цвет.*}
ПОМЕСТИТЬ ВТ_Свойства
ИЗ
Справочник.Номенклатура.ДополнительныеРеквизиты КАК НоменклатураДополнительныеРеквизиты
ГДЕ
НоменклатураДополнительныеРеквизиты.Свойство.Наименование = &НаименованиеЦвет
{ГДЕ НоменклатураДополнительныеРеквизиты.Значение КАК Цвет}
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
НоменклатураДополнительныеРеквизиты.Ссылка,
NULL,
НоменклатураДополнительныеРеквизиты.Значение
{ВЫБРАТЬ Номенклатура.*, Размер.*}
ИЗ
Справочник.Номенклатура.ДополнительныеРеквизиты КАК НоменклатураДополнительныеРеквизиты
ГДЕ
НоменклатураДополнительныеРеквизиты.Свойство.Наименование = &НаименованиеРазмер
{ГДЕ НоменклатураДополнительныеРеквизиты.Значение КАК Размер}
Обратите внимание на конструкцию в фигурных скобках {ГДЕ ...}. Благодаря ручной разметке мы явно указали оптимизатору СКД:
Цвет должен накладываться только в первой ветке объединения.Размер должен накладываться только во второй ветке объединения.В результате СКД больше не будет бездумно проталкивать оба условия во все ветки подряд, и множественный отбор снова заработает корректно, возвращая заполненную таблицу.
Резюме: для долгосрочной и стабильной работы отчетов в современных версиях платформы 1С рекомендуется использовать штатный механизм Характеристик (Вариант 1) или переходить на схему построения запросов через Левые соединения (Вариант 2). Использование ручного управления отборами через отключение автозаполнения (Вариант 3) отлично подходит в качестве быстрого исправления «горящих» ошибок в уже существующих сложных отчетах пользователей.