Как подключить дополнительные свойства объектов в запросе 1С без потери данных и дублирования строк?

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

При разработке и кастомизации отчетов в конфигурации «1С:Управление производственным предприятием 1.3» (УПП) разработчики часто сталкиваются с необходимостью вывода дополнительных свойств объектов. Эти свойства хранятся в плане видов характеристик СвойстваОбъектов и регистре сведений ЗначенияСвойствОбъектов. Типичный сценарий — вывести в списке сотрудников компании не только базовые кадровые данные, но и привязанные к ним или к их приказам свойства, такие как «Премия», «Департамент» или «ГД».

Однако при попытке связать основную таблицу запроса с регистром значений свойств начинающие разработчики часто совершают две критические ошибки: либо из отчета полностью пропадают сотрудники, у которых свойства не заполнены, либо строки отчета начинают хаотично дублироваться. В этой статье мы подробно разберем причины возникновения этих проблем и рассмотрим три профессиональных архитектурных решения, которые позволят построить надежный и быстродействующий отчет.

Выясняем причину: почему пропадают сотрудники или двоятся строки?

Проанализируем две типичные ошибки, которые наглядно представлены в сообщениях форума.

Ошибка №1: Превращение левого соединения во внутреннее. В первом сообщении автор пытается присоединить таблицу свойств и накладывает условие фильтрации в секции ГДЕ:


ГДЕ
    ЗначенияСвойствОбъектов2.Свойство = &свойствоПремия

Когда СУБД выполняет ЛЕВОЕ СОЕДИНЕНИЕ, она берет всех сотрудников и сопоставляет им свойства. Если у сотрудника нет свойства «Премия», то во всех полях присоединяемой таблицы ЗначенияСвойствОбъектов2 для этого сотрудника будет возвращено значение NULL. На следующем этапе выполнения запроса срабатывает секция ГДЕ, которая проверяет условие: ЗначенияСвойствОбъектов2.Свойство = &свойствоПремия. Поскольку NULL = &свойствоПремия дает результат Ложь (или NULL), строка с этим сотрудником полностью отсекается из итоговой выборки. В итоге левое соединение фактически превращается во ВНУТРЕННЕЕ СОЕДИНЕНИЕ, и отчет формируется только по тем сотрудникам, у которых жестко заполнено это свойство.

Ошибка №2: Декартово произведение (умножение строк). Пытаясь обойти первую ошибку, разработчик добавляет несколько левых соединений к одной и той же таблице ЗначенияСвойствОбъектов для разных свойств (например, для ЗП, Департамента и ГД), но связывает их только по полю Объект:


ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектовДепартамент
    ПО ПриказыОПриеме.Приказ = ЗначенияСвойствОбъектовДепартамент.Объект

Поскольку у одного приказа в базе данных может быть назначено множество различных свойств (не только Департамент, но и любые другие характеристики), такое соединение без указания конкретного свойства в условии связи ПО возвращает абсолютно все свойства этого приказа. СУБД генерирует избыточное количество комбинаций строк (декартово произведение), из-за чего данные в отчете начинают удваиваться, утраиваться и выводиться в хаотичном виде.

Давайте разберем по шагам, какими способами можно решить эти проблемы правильно.

Решение 1. Перенос условий фильтрации в секцию связи (ПО)

Самый простой и быстрый способ исправить логику запроса — перенести условия отбора по конкретным свойствам непосредственно в секцию ПО левого соединения. В этом случае СУБД сначала отфильтрует записи регистра свойств по нужному виду характеристики, а затем выполнит левое соединение уже с отфильтрованным набором данных. Если у сотрудника (или приказа) нет нужного свойства, строка не исчезнет, а поле значения просто останется пустым.

Рассмотрим подробнее пример реализации этого подхода в запросе:


ВЫБРАТЬ РАЗРЕШЕННЫЕ
    Работники.ФизЛицо КАК ФизЛицо,
    Работники.Подразделение КАК Подразделение,
    Работники.Должность КАК Должность,
    ЗначенияСвойствЗП.Значение КАК ЗПИтогоБезНоминала,
    ЗначенияСвойствДепартамент.Значение КАК Департамент,
    ЗначенияСвойствГД.Значение КАК ГД
ИЗ
    РегистрСведений.Работники.СрезПоследних(&Период, ) КАК Работники
    
    // Переносим условия по свойствам непосредственно в секцию ПО каждого соединения
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствЗП
        ПО Работники.ФизЛицо = ЗначенияСвойствЗП.Объект
        И ЗначенияСвойствЗП.Свойство = &парамсвойство

    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствДепартамент
        ПО Работники.ФизЛицо = ЗначенияСвойствДепартамент.Объект
        И ЗначенияСвойствДепартамент.Свойство = &парамДепарт

    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствГД
        ПО Работники.ФизЛицо = ЗначенияСвойствГД.Объект
        И ЗначенияСвойствГД.Свойство = &парамГД

При таком подходе секция ГДЕ остается абсолютно чистой от условий по присоединяемым таблицам свойств. Данные выводятся корректно, без дублей и потерь сотрудников.

Решение 2. Разворот свойств (Pivot) через Временную Таблицу (Рекомендуемый вариант)

Хотя первый метод прост в реализации, у него есть существенный недостаток с точки зрения производительности СУБД. Если вам нужно вывести 5-10 различных свойств, вам придется написать 5-10 левых соединений к одной и той же таблице регистра ЗначенияСвойствОбъектов. На больших базах данных это приведет к серьезному замедлению работы отчета.

Профессиональный подход заключается в том, чтобы выбрать все необходимые свойства за один проход по регистру во временную таблицу, «развернув» их строки в колонки (реализовав аналог операции Pivot) с помощью группировки и агрегатной функции МАКСИМУМ. А затем выполнить всего одно левое соединение с этой временной таблицей.

Разберем этот метод подробно по шагам:

  1. Создаем временную таблицу, в которой группируем записи регистра свойств по объекту (физлицу или приказу) и распределяем значения свойств по колонкам с помощью конструкции ВЫБОР КОГДА.
  2. В основном запросе соединяем полученную временную таблицу с основной таблицей сотрудников по ключу связи.

Посмотрим на пример практической реализации данного алгоритма в коде запроса:


// Шаг 1: Подготавливаем развернутую таблицу свойств во временной таблице
ВЫБРАТЬ
    РегистрСвойств.Объект КАК Объект,
    МАКСИМУМ(ВЫБОР КОГДА РегистрСвойств.Свойство = &парамсвойство ТОГДА РегистрСвойств.Значение КОНЕЦ) КАК ЗПИтогоБезНоминала,
    МАКСИМУМ(ВЫБОР КОГДА РегистрСвойств.Свойство = &парамДепарт ТОГДА РегистрСвойств.Значение КОНЕЦ) КАК Департамент,
    МАКСИМУМ(ВЫБОР КОГДА РегистрСвойств.Свойство = &парамГД ТОГДА РегистрСвойств.Значение КОНЕЦ) КАК ГД
ПОМЕСТИТЬ ВТ_СвойстваСотрудников
ИЗ
    РегистрСведений.ЗначенияСвойствОбъектов КАК РегистрСвойств
ГДЕ
    РегистрСвойств.Свойство В (&СписокНужныхСвойств)
СГРУППИРОВАТЬ ПО
    РегистрСвойств.Объект
;

////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Основной запрос отчета
ВЫБРАТЬ РАЗРЕШЕННЫЕ
    Работники.ФизЛицо КАК ФизЛицо,
    Работники.Подразделение КАК Подразделение,
    Работники.Должность КАК Должность,
    ЕСТЬNULL(ВТ_Свойства.ЗПИтогоБезНоминала, 0) КАК ЗПИтогоБезНоминала,
    ВТ_Свойства.Департамент КАК Департамент,
    ВТ_Свойства.ГД КАК ГД
ИЗ
    РегистрСведений.Работники.СрезПоследних(&Период, ) КАК Работники
    
    // Всего одно легкое левое соединение вместо множественных связей к регистру сведений
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_СвойстваСотрудников КАК ВТ_Свойства
        ПО Работники.ФизЛицо = ВТ_Свойства.Объект

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

Решение 3. Использование механизма Характеристик в СКД

Если ваш отчет разрабатывается на Системе компоновки данных (СКД), то платформа 1С предоставляет мощный встроенный механизм для динамического подключения свойств — Характеристики. При его использовании вам вообще не нужно вручную прописывать левые соединения с таблицей регистра свойств в тексте запроса.

Для настройки характеристик выполните следующие шаги в конструкторе схемы компоновки данных:

  1. Откройте вкладку «Характеристики» на уровне набора данных или воспользуйтесь специальным конструктором.
  2. Для типа объекта СправочникСсылка.ФизическиеЛица (или любого другого справочника, свойства которого вы хотите получить) укажите источник видов характеристик. Это будет запрос к плану видов характеристик СвойстваОбъектов.
  3. Укажите источник значений характеристик — регистр сведений ЗначенияСвойствОбъектов, связав его по полю Объект.
  4. Задайте соответствие ключевых полей (Идентификатор, Имя характеристики, Значение, Свойство/Вид).

После такой настройки платформа 1С автоматически добавит все существующие в вашей системе дополнительные свойства (включая «Премия», «Департамент» и др.) в список доступных полей отчета СКД. Пользователь сможет самостоятельно перетаскивать их в группировки, колонки или использовать в отборах. При этом платформа сама на лету сгенерирует наиболее оптимальный SQL-запрос с левыми соединениями, гарантируя отсутствие дублей и сохранение всех строк отчета.

Важное примечание: В коде запроса автора темы уже присутствует описание характеристик в фигурных скобках {ХАРАКТЕРИСТИКИ}. Это означает, что механизм уже частично настроен. Вместо написания тяжелых ручных соединений в тексте запроса разработчику было достаточно просто выбрать эти характеристики на вкладке настроек СКД в режиме конфигуратора или в пользовательских настройках отчета.

Используйте предложенные архитектурные варианты в своей практике для создания качественных, расширяемых и высокопроизводительных отчетов в среде 1С:Предприятие!

← На главную