Почему в отчете задваиваются сотрудники при выводе адреса и как исправить запрос в 1С?

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

При разработке кадровых отчетов и реестров в 1С часто возникает ситуация, когда одна строка кадрового события (прием, увольнение, перемещение) дублируется несколько раз. В исходном примере реестр принятых и уволенных сотрудников задваивает или затраивает строки, если у физического лица заполнено несколько разных адресов (по прописке, проживания, для информирования).

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

Причина задвоения данных

В типовых конфигурациях (1С:ЗУП 3, 1С:ERP, 1С:КА) у одного физического лица может быть сохранено сразу несколько адресов с типом Адрес:

  1. Адрес по прописке (регистрации)
  2. Адрес места проживания фактический
  3. Адрес для информирования
  4. Адрес за пределами РФ

В исходном запросе автора во вложенной выборке накладывается условие только на тип контактной информации:


ГДЕ
    ФизическиеЛицаКонтактнаяИнформация.Вид.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Адрес)

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

Кроме того, в исходном запросе использовалось ПОЛНОЕ СОЕДИНЕНИЕ, из-за чего сотрудники без адреса или физлица без кадровых записей могли сформировать некорректную выборку, а также присутствовало избыточное соединение табличной части КонтактнаяИнформация с самой шапкой справочника ФизическиеЛица.

Способ 1. Отбор по конкретному виду контактной информации

Если в реестре требуется вывести строго определенный адрес (например, адрес по прописке), необходимо делать соединение не по общему типу, а по конкретному предопределенному элементу справочника ВидыКонтактнойИнформации. Также заменим полное соединение на ЛЕВОЕ СОЕДИНЕНИЕ, чтобы кадровые события выводились даже при незаполненном адресе.

Посмотрим на исправленный текст запроса:


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

Способ 2. Приоритетный выбор адреса при отсутствии основного

Если по регламенту нужно выводить адрес регистрации, но если он не заполнен — выводить фактический адрес проживания, используем два отдельных левых соединения с функцией ЕСТЬNULL.

Разберем пример:


ВЫБРАТЬ
    КадроваяИстория.Сотрудник КАК Сотрудник,
    КадроваяИстория.ФизическоеЛицо КАК ФизическоеЛицо,
    КадроваяИстория.ВидСобытия КАК ВидСобытия,
    КадроваяИстория.Период КАК ДатаСобытия,
    ЕСТЬNULL(АдресПрописки.Представление, АдресПроживания.Представление) КАК Адрес
ИЗ
    РегистрСведений.КадроваяИсторияСотрудников КАК КадроваяИстория
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ФизическиеЛица.КонтактнаяИнформация КАК АдресПрописки
        ПО КадроваяИстория.ФизическоеЛицо = АдресПрописки.Ссылка
        И (АдресПрописки.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.АдресПоПропискеФизическиеЛица))
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ФизическиеЛица.КонтактнаяИнформация КАК АдресПроживания
        ПО КадроваяИстория.ФизическоеЛицо = АдресПроживания.Ссылка
        И (АдресПроживания.Вид = ЗНАЧЕНИЕ(Справочник.ВидыКонтактнойИнформации.АдресПроживанияФизическиеЛица))
ГДЕ
    КадроваяИстория.Период МЕЖДУ &НачПериода И &КонПериода
    И КадроваяИстория.ВидСобытия <> ЗНАЧЕНИЕ(Перечисление.ВидыКадровыхСобытий.Перемещение)

Способ 3. Вывод всех адресов в одну строку через СКД

Если в отчет требуется вывести все заполненные адреса физического лица, но без размножения кадровых строк, настроим агрегацию в схеме компоновки данных. Для этого в запросе связываем данные с отбором по типу Адрес, а на вкладке Ресурсы для поля Адрес задаем выражение:

СоединитьСтроки(Адрес, "; ")

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

Способ 4. Использование типовых программных интерфейсов (API ЗУП 3)

В типовых конфигурациях для получения кадровой информации и персональных данных рекомендуется использовать штатные модули БСП и подсистемы зарплаты вместо прямых запросов к регистрам:

  1. Функция подсистемы кадрового учета: с помощью КадровыйУчет.КадровыеДанныеСотрудников() или КадровыйУчет.КадровыеДанныеФизическихЛиц() можно передать массив сотрудников и список запрашиваемых полей (например, "АдресПоПропискеПредставление", "ДатаПриема", "ДатаРождения"). Функция вернет готовую таблицу значений с гарантией отсутствия дублей.
  2. Функция подсистемы контактной информации: для точечного получения данных по конкретному физлицу используется вызов УправлениеКонтактнойИнформацией.КонтактнаяИнформацияОбъекта().

Оптимизация обращений к регистратору

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

← На главную