При разработке и кастомизации отчетов в конфигурации «1С:Управление производственным предприятием 1.3» (УПП) разработчики часто сталкиваются с необходимостью вывода дополнительных свойств объектов. Эти свойства хранятся в плане видов характеристик СвойстваОбъектов и регистре сведений ЗначенияСвойствОбъектов. Типичный сценарий — вывести в списке сотрудников компании не только базовые кадровые данные, но и привязанные к ним или к их приказам свойства, такие как «Премия», «Департамент» или «ГД».
Однако при попытке связать основную таблицу запроса с регистром значений свойств начинающие разработчики часто совершают две критические ошибки: либо из отчета полностью пропадают сотрудники, у которых свойства не заполнены, либо строки отчета начинают хаотично дублироваться. В этой статье мы подробно разберем причины возникновения этих проблем и рассмотрим три профессиональных архитектурных решения, которые позволят построить надежный и быстродействующий отчет.
Проанализируем две типичные ошибки, которые наглядно представлены в сообщениях форума.
Ошибка №1: Превращение левого соединения во внутреннее. В первом сообщении автор пытается присоединить таблицу свойств и накладывает условие фильтрации в секции ГДЕ:
ГДЕ
ЗначенияСвойствОбъектов2.Свойство = &свойствоПремия
Когда СУБД выполняет ЛЕВОЕ СОЕДИНЕНИЕ, она берет всех сотрудников и сопоставляет им свойства. Если у сотрудника нет свойства «Премия», то во всех полях присоединяемой таблицы ЗначенияСвойствОбъектов2 для этого сотрудника будет возвращено значение NULL. На следующем этапе выполнения запроса срабатывает секция ГДЕ, которая проверяет условие: ЗначенияСвойствОбъектов2.Свойство = &свойствоПремия. Поскольку NULL = &свойствоПремия дает результат Ложь (или NULL), строка с этим сотрудником полностью отсекается из итоговой выборки. В итоге левое соединение фактически превращается во ВНУТРЕННЕЕ СОЕДИНЕНИЕ, и отчет формируется только по тем сотрудникам, у которых жестко заполнено это свойство.
Ошибка №2: Декартово произведение (умножение строк). Пытаясь обойти первую ошибку, разработчик добавляет несколько левых соединений к одной и той же таблице ЗначенияСвойствОбъектов для разных свойств (например, для ЗП, Департамента и ГД), но связывает их только по полю Объект:
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектовДепартамент
ПО ПриказыОПриеме.Приказ = ЗначенияСвойствОбъектовДепартамент.Объект
Поскольку у одного приказа в базе данных может быть назначено множество различных свойств (не только Департамент, но и любые другие характеристики), такое соединение без указания конкретного свойства в условии связи ПО возвращает абсолютно все свойства этого приказа. СУБД генерирует избыточное количество комбинаций строк (декартово произведение), из-за чего данные в отчете начинают удваиваться, утраиваться и выводиться в хаотичном виде.
Давайте разберем по шагам, какими способами можно решить эти проблемы правильно.
Самый простой и быстрый способ исправить логику запроса — перенести условия отбора по конкретным свойствам непосредственно в секцию ПО левого соединения. В этом случае СУБД сначала отфильтрует записи регистра свойств по нужному виду характеристики, а затем выполнит левое соединение уже с отфильтрованным набором данных. Если у сотрудника (или приказа) нет нужного свойства, строка не исчезнет, а поле значения просто останется пустым.
Рассмотрим подробнее пример реализации этого подхода в запросе:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
Работники.ФизЛицо КАК ФизЛицо,
Работники.Подразделение КАК Подразделение,
Работники.Должность КАК Должность,
ЗначенияСвойствЗП.Значение КАК ЗПИтогоБезНоминала,
ЗначенияСвойствДепартамент.Значение КАК Департамент,
ЗначенияСвойствГД.Значение КАК ГД
ИЗ
РегистрСведений.Работники.СрезПоследних(&Период, ) КАК Работники
// Переносим условия по свойствам непосредственно в секцию ПО каждого соединения
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствЗП
ПО Работники.ФизЛицо = ЗначенияСвойствЗП.Объект
И ЗначенияСвойствЗП.Свойство = &парамсвойство
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствДепартамент
ПО Работники.ФизЛицо = ЗначенияСвойствДепартамент.Объект
И ЗначенияСвойствДепартамент.Свойство = &парамДепарт
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствГД
ПО Работники.ФизЛицо = ЗначенияСвойствГД.Объект
И ЗначенияСвойствГД.Свойство = &парамГД
При таком подходе секция ГДЕ остается абсолютно чистой от условий по присоединяемым таблицам свойств. Данные выводятся корректно, без дублей и потерь сотрудников.
Хотя первый метод прост в реализации, у него есть существенный недостаток с точки зрения производительности СУБД. Если вам нужно вывести 5-10 различных свойств, вам придется написать 5-10 левых соединений к одной и той же таблице регистра ЗначенияСвойствОбъектов. На больших базах данных это приведет к серьезному замедлению работы отчета.
Профессиональный подход заключается в том, чтобы выбрать все необходимые свойства за один проход по регистру во временную таблицу, «развернув» их строки в колонки (реализовав аналог операции Pivot) с помощью группировки и агрегатной функции МАКСИМУМ. А затем выполнить всего одно левое соединение с этой временной таблицей.
Разберем этот метод подробно по шагам:
ВЫБОР КОГДА.Посмотрим на пример практической реализации данного алгоритма в коде запроса:
// Шаг 1: Подготавливаем развернутую таблицу свойств во временной таблице
ВЫБРАТЬ
РегистрСвойств.Объект КАК Объект,
МАКСИМУМ(ВЫБОР КОГДА РегистрСвойств.Свойство = &парамсвойство ТОГДА РегистрСвойств.Значение КОНЕЦ) КАК ЗПИтогоБезНоминала,
МАКСИМУМ(ВЫБОР КОГДА РегистрСвойств.Свойство = &парамДепарт ТОГДА РегистрСвойств.Значение КОНЕЦ) КАК Департамент,
МАКСИМУМ(ВЫБОР КОГДА РегистрСвойств.Свойство = &парамГД ТОГДА РегистрСвойств.Значение КОНЕЦ) КАК ГД
ПОМЕСТИТЬ ВТ_СвойстваСотрудников
ИЗ
РегистрСведений.ЗначенияСвойствОбъектов КАК РегистрСвойств
ГДЕ
РегистрСвойств.Свойство В (&СписокНужныхСвойств)
СГРУППИРОВАТЬ ПО
РегистрСвойств.Объект
;
////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Основной запрос отчета
ВЫБРАТЬ РАЗРЕШЕННЫЕ
Работники.ФизЛицо КАК ФизЛицо,
Работники.Подразделение КАК Подразделение,
Работники.Должность КАК Должность,
ЕСТЬNULL(ВТ_Свойства.ЗПИтогоБезНоминала, 0) КАК ЗПИтогоБезНоминала,
ВТ_Свойства.Департамент КАК Департамент,
ВТ_Свойства.ГД КАК ГД
ИЗ
РегистрСведений.Работники.СрезПоследних(&Период, ) КАК Работники
// Всего одно легкое левое соединение вместо множественных связей к регистру сведений
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_СвойстваСотрудников КАК ВТ_Свойства
ПО Работники.ФизЛицо = ВТ_Свойства.Объект
Этот метод гарантирует абсолютную стабильность запроса, полное отсутствие дублирования строк и максимальную скорость выполнения отчета даже в базах с миллионами записей.
Если ваш отчет разрабатывается на Системе компоновки данных (СКД), то платформа 1С предоставляет мощный встроенный механизм для динамического подключения свойств — Характеристики. При его использовании вам вообще не нужно вручную прописывать левые соединения с таблицей регистра свойств в тексте запроса.
Для настройки характеристик выполните следующие шаги в конструкторе схемы компоновки данных:
СправочникСсылка.ФизическиеЛица (или любого другого справочника, свойства которого вы хотите получить) укажите источник видов характеристик. Это будет запрос к плану видов характеристик СвойстваОбъектов.ЗначенияСвойствОбъектов, связав его по полю Объект.После такой настройки платформа 1С автоматически добавит все существующие в вашей системе дополнительные свойства (включая «Премия», «Департамент» и др.) в список доступных полей отчета СКД. Пользователь сможет самостоятельно перетаскивать их в группировки, колонки или использовать в отборах. При этом платформа сама на лету сгенерирует наиболее оптимальный SQL-запрос с левыми соединениями, гарантируя отсутствие дублей и сохранение всех строк отчета.
Важное примечание: В коде запроса автора темы уже присутствует описание характеристик в фигурных скобках {ХАРАКТЕРИСТИКИ}. Это означает, что механизм уже частично настроен. Вместо написания тяжелых ручных соединений в тексте запроса разработчику было достаточно просто выбрать эти характеристики на вкладке настроек СКД в режиме конфигуратора или в пользовательских настройках отчета.
Используйте предложенные архитектурные варианты в своей практике для создания качественных, расширяемых и высокопроизводительных отчетов в среде 1С:Предприятие!