При разработке отчетов и проведении документов в конфигурациях 1С (таких как УПП 1.3, ЗУП 2.5, КА 1.1 и др.) разработчики часто сталкиваются со ситуацией, когда по одному и тому же человеку в выборку попадает несколько строк. Проанализируем, почему возникает эта проблема и как правильно составить запрос, чтобы получить ровно одну запись с последней актуальной датой кадрового изменения.
Рассмотрим устройство учетных механизмов 1С. Данные о людях разделены на два уровня:
ФизическиеЛица — содержит персональные данные человека (ФИО, ИНН, паспортные данные). Для каждого человека создается строго один элемент.Сотрудники — отражает трудовой договор. Если человек уволился, а затем через какое-то время снова принят на работу (или работает по внутреннему совместительству), на одно физическое лицо создается два или более элементов справочника Сотрудники.Кадровые изменения хранятся в регистрах сведений (например, РаботникиОрганизаций). Измерением таких регистров является Сотрудник, а не ФизЛицо. Когда мы обращаемся к виртуальной таблице СрезПоследних или к самому регистру сведений и связываем его по реквизиту Сотрудник.Физлицо, система находит последнее кадровое состояние для каждого трудового договора данного человека. В результате по одному физическому лицу выводится столько строк, сколько раз он принимался на работу.
Выясним, почему наиболее очевидные решения не работают в данной ситуации:
ПЕРВЫЕ 1 и УПОРЯДОЧИТЬ ПО Период УБЫВ:
Конструкция ПЕРВЫЕ 1 срезáет количество строк во всем результате запроса. Если в документе указано 10 разных людей, то при использовании ПЕРВЫЕ 1 запрос вернет только одну запись для первого попавшегося человека, а остальные сотрудники из документа вообще не попадут в результат.Сотрудник с функцией МАКСИМУМ(Период):
Если в группировке участвует поле Сотрудник, функция МАКСИМУМ(Период) вернет максимальную дату для каждого конкретного элемента справочника Сотрудники. Поскольку у человека 2 разных сотрудника, группировка по-прежнему вернет 2 строки.Сотрудник.Актуальность = ИСТИНА:
Флаг архивности сотрудника не всегда корректно меняется при повторном приеме на работу или может зависеть от специфики заполнения справочников пользователями, поэтому данный критерий не является гарантией защиты от дублей.Для гарантированного получения одной последней записи на каждое физическое лицо необходимо построить двухэтапный запрос с использованием временных таблиц.
Разберем процесс по шагам:
ФизЛицо из табличной части документа или источника данных.Регистр.Сотрудник.Физлицо = ВТ.ФизЛицо. Делаем группировку строго по полю ФизЛицо и рассчитываем МАКСИМУМ(Период) с учетом ограничения по дате среза.ФизЛицо и по максимальному периоду.Рассмотрим практическую реализацию этого алгоритма на языке запросов 1С:
ВЫБРАТЬ РАЗЛИЧНЫЕ
ПередачаМатериалов.ФизЛицо КАК ФизЛицо
ПОМЕСТИТЬ ВТ_ФизЛицаДокумента
ИЗ
Документ.ПередачаМатериаловВЭксплуатацию.Материалы КАК ПередачаМатериалов
ГДЕ
ПередачаМатериалов.Ссылка = &ТекущийДокумент
И НЕ ПередачаМатериалов.ФизЛицо ЕСТЬ NULL
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ФизЛица.ФизЛицо КАК ФизЛицо,
МАКСИМУМ(РаботникиОрганизаций.Период) КАК МаксПериод
ПОМЕСТИТЬ ВТ_МаксимальныеДаты
ИЗ
ВТ_ФизЛицаДокумента КАК ВТ_ФизЛица
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.РаботникиОрганизаций КАК РаботникиОрганизаций
ПО ВТ_ФизЛица.ФизЛицо = РаботникиОрганизаций.Сотрудник.Физлицо
ГДЕ
РаботникиОрганизаций.Период <= &Дат
И РаботникиОрганизаций.Активность = ИСТИНА
СГРУППИРОВАТЬ ПО
ВТ_ФизЛица.ФизЛицо
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_Даты.ФизЛицо КАК ФизЛицо,
РаботникиОрганизаций.Сотрудник КАК Сотрудник,
РаботникиОрганизаций.Должность КАК Должность,
РаботникиОрганизаций.ПодразделениеОрганизации КАК Подразделение,
ВТ_Даты.МаксПериод КАК Период
ИЗ
ВТ_МаксимальныеДаты КАК ВТ_Даты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.РаботникиОрганизаций КАК РаботникиОрганизаций
ПО ВТ_Даты.ФизЛицо = РаботникиОрганизаций.Сотрудник.Физлицо
И ВТ_Даты.МаксПериод = РаботникиОрганизаций.Период
Проанализируем редкую ситуацию: что если по какому-то человеку в регистре сведений оформлено два документа с абсолютно одинаковой датой и временем секунда в секунду (например, увольнение по одному договору и прием по другому произошли в 00:00:00)?
В этом случае условие ВТ_Даты.МаксПериод = РаботникиОрганизаций.Период вернет 2 записи. Чтобы полностью исключить вероятность раздваивания строк при совпадении дат, во второй временной таблице вместе с максимальным периодом можно дополнительно рассчитывать максимальный элемент сотрудника:
ВЫБРАТЬ
ВТ_ФизЛица.ФизЛицо КАК ФизЛицо,
МАКСИМУМ(РаботникиОрганизаций.Период) КАК МаксПериод,
МАКСИМУМ(РаботникиОрганизаций.Сотрудник) КАК МаксСотрудник
ПОМЕСТИТЬ ВТ_МаксимальныеДаты
ИЗ
ВТ_ФизЛицаДокумента КАК ВТ_ФизЛица
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.РаботникиОрганизаций КАК РаботникиОрганизаций
ПО ВТ_ФизЛица.ФизЛицо = РаботникиОрганизаций.Сотрудник.Физлицо
ГДЕ
РаботникиОрганизаций.Период <= &Дат
И РаботникиОрганизаций.Активность = ИСТИНА
СГРУППИРОВАТЬ ПО
ВТ_ФизЛица.ФизЛицо
И при финальном соединении накладывать условие сразу по трем полям: ФизЛицо, Период и Сотрудник. Такой подход обеспечивает абсолютную уникальность получаемых строк по каждому физическому лицу.