При заполнении табличных частей документов и формировании кадровых отчетов часто требуется определить текущее подразделение или должность физического лица. Если строить сложный запрос с агрегатными функциями и вложенными подзапросами, легко получить дублирование строк или некорректные исторические значения. Разберем типичные ошибки таких запросов и пошагово построим правильные варианты выборки данных.
Проанализируем структуру запроса, в котором разработчики пытаются вручную вычислить срез кадровых данных без использования стандартных возможностей платформы 1С:
МАКСИМУМ: использование конструкций вида МАКСИМУМ(РаботникиОрганизаций.ПодразделениеОрганизации) в сгруппированном запросе возвращает не подразделение на последнюю дату, а ссылку с максимальным внутренним идентификатором (GUID) или строковым представлением. В результате выбирается случайное историческое подразделение.ПО (ИСТИНА): вложенный запрос без группировки по физическим лицам находит одну общую максимальную дату по всей таблице регистра. Соединение по условию ИСТИНА создает декартово произведение, искажая результаты выборки.РаботникиОрганизаций) является Сотрудник, а Физлицо выступает реквизитом сотрудника. Одно физическое лицо может иметь несколько элементов в справочнике Сотрудники (при повторном приеме, совместительстве или договорах ГПХ).Рассмотрим базовый и наиболее компактный вариант запроса. Если необходимо заполнить подразделения для строк табличной части документа, используем виртуальную таблицу СрезПоследних регистра сведений с фильтрацией по дате документа.
ВЫБРАТЬ
ДокТЧ.ФизЛицо КАК ФизЛицо,
ДокТЧ.ФизЛицо.ИдентификационныйКодЛичности КАК ИИНРаботника,
ДокТЧ.ФизЛицо.РНН КАК РННРаботника,
РаботникиОрганизацийСрезПоследних.Сотрудник КАК Сотрудник,
РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизации КАК Подразделение,
РаботникиОрганизацийСрезПоследних.Должность КАК Должность
ИЗ
Документ.РасчетСНиСО.ИсчисленныеООСМС КАК ДокТЧ
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.РаботникиОрганизаций.СрезПоследних(
&Период,
Организация = &Организация
И Сотрудник.ВидЗанятости <> &ВнутреннееСовместительство
) КАК РаботникиОрганизацийСрезПоследних
ПО (РаботникиОрганизацийСрезПоследних.Сотрудник.Физлицо = ДокТЧ.ФизЛицо)
ГДЕ
ДокТЧ.Ссылка = &Ссылка
Посмотрим на параметры этого запроса: в виртуальную таблицу передается &Период (дата актуальности или дата документа) и условие отбора по организации и основному месту работы. Это отсекает лишние записи и совместителей.
Разберем по шагам более производительный и надежный сценарий, когда в регистре сведений измерением является Сотрудник, а связь с документом строится по ФизЛицо. Чтобы СУБД не выполняла полный срез по всей базе, поместим физические лица во временную таблицу и выполним точечный срез.
ВТ_ФизЛица.
ВЫБРАТЬ РАЗЛИЧНЫЕ
ДокТЧ.ФизЛицо КАК ФизЛицо
ПОМЕСТИТЬ ВТ_ФизЛица
ИЗ
Документ.РасчетСНиСО.ИсчисленныеООСМС КАК ДокТЧ
ГДЕ
ДокТЧ.Ссылка = &Ссылка
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
РаботникиОрганизаций.Организация КАК Организация,
РаботникиОрганизаций.Сотрудник.Физлицо КАК ФизЛицо,
МАКСИМУМ(РаботникиОрганизаций.Период) КАК Период
ПОМЕСТИТЬ ВТ_МаксимальныеПериоды
ИЗ
РегистрСведений.РаботникиОрганизаций КАК РаботникиОрганизаций
ГДЕ
РаботникиОрганизаций.Организация = &Организация
И РаботникиОрганизаций.Период <= &Период
И РаботникиОрганизаций.Сотрудник.Физлицо В
(ВЫБРАТЬ ВТ.ФизЛицо ИЗ ВТ_ФизЛица КАК ВТ)
И РаботникиОрганизаций.Сотрудник.ВидЗанятости <> &ВнутреннееСовместительство
СГРУППИРОВАТЬ ПО
РаботникиОрганизаций.Организация,
РаботникиОрганизаций.Сотрудник.Физлицо
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ФизЛица.ФизЛицо КАК ФизЛицо,
РаботникиОрганизаций.Сотрудник КАК Сотрудник,
РаботникиОрганизаций.ПодразделениеОрганизации КАК Подразделение,
РаботникиОрганизаций.Должность КАК Должность
ИЗ
ВТ_ФизЛица КАК ВТ_ФизЛица
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_МаксимальныеПериоды КАК Периоды
ПО (Периоды.ФизЛицо = ВТ_ФизЛица.ФизЛицо)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.РаботникиОрганизаций КАК РаботникиОрганизаций
ПО (РаботникиОрганизаций.Организация = Периоды.Организация)
И (РаботникиОрганизаций.Период = Периоды.Период)
И (РаботникиОрганизаций.Сотрудник.Физлицо = Периоды.ФизЛицо)
Выясним причину возможных расхождений и правила их предотвращения:
ПричинаИзмененияСостояния <> &ПарамУволен).КадровыйУчет), которые учитывают все нюансы стажей, совмещений и кадровых перемещений.
Отбор = Новый Структура;
Отбор.Вставить("Организация", ГоловнаяОрганизация);
Отбор.Вставить("Сотрудник", ТекущийСотрудник);
Срез = РегистрыСведений.РаботникиОрганизаций.СрезПоследних(ДатаАктуальности, Отбор);
Если Срез.Количество() > 0 Тогда
ТекущееПодразделение = Срез[0].ПодразделениеОрганизации;
КонецЕсли;