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