При разработке отчетов или обработок выгрузки в конфигурации 1С:Зарплата и Управление Персоналом 3.1 программисты часто сталкиваются с проблемой дублирования строк. Типичная ситуация: сотрудник увольнялся и принимался на работу снова. В регистрах сведений 1С по такому человеку хранится несколько записей, и обычный запрос к срезу последних или кадровой истории может вернуть обе строки. Если нам нужна только актуальная информация (последнее место работы), лишние данные необходимо отсечь.
В этой статье мы подробно разберем несколько стратегий решения этой задачи: от простых манипуляций с кодом обхода до использования мощных встроенных инструментов платформы и конфигурации.
Прежде чем исправлять код, проанализируем ситуацию. В ЗУП 3.1 понятия ФизическоеЛицо и Сотрудник разделены. Одно физлицо может иметь несколько карточек сотрудников (основное место работы, внутреннее совместительство, или новая карточка после увольнения). Если в запросе соединение идет по полю ФизическоеЛицо, система честно выбирает все связанные записи. Наша задача — оставить только ту запись, которая является наиболее актуальной на текущий момент.
Это самый простой способ, если вы не хотите глубоко переписывать сложный запрос. Суть метода заключается в том, чтобы предварительно отсортировать данные и при записи в файл проверять, не обрабатывали ли мы этого человека ранее.
Рассмотрим по шагам, как модифицировать алгоритм:
ФизическоеЛицо и по убыванию ДатаПриема. Таким образом, самая свежая запись по каждому человеку окажется первой в списке.Посмотрим на пример кода:
// Сначала сортируем таблицу, чтобы актуальные записи были сверху
ТЗ.Сортировать("ФизическоеЛицо Возр, ДатаПриема Убыв");
ПоследнееФизЛицо = Неопределено;
ТекстCSV = "";
Для Каждого СтрокаТЗ Из ТЗ Цикл
// Если это тот же человек, что и в прошлой строке - игнорируем
Если СтрокаТЗ.ФизическоеЛицо = ПоследнееФизЛицо Тогда
Продолжить;
КонецЕсли;
// Запоминаем текущее лицо как последнее обработанное
ПоследнееФизЛицо = СтрокаТЗ.ФизическоеЛицо;
// Формируем строку CSV
ТекстCSV = ТекстCSV + СтрокаТЗ.ФизическоеЛицоФамилия + "," + СтрокаТЗ.Должность + Символы.ПС;
КонецЦикла;
Важный нюанс: этот метод эффективен, когда данных не слишком много. Если вы выгружаете десятки тысяч сотрудников, сортировка и перебор в памяти могут занять время.
Более профессиональный подход — избавиться от дублей еще на этапе выполнения запроса к базе данных. Это сэкономит ресурсы сервера и упростит дальнейшую обработку данных. Мы можем использовать механизм группировок или временных таблиц для получения последних дат событий.
Проанализируем ситуацию: нам нужно получить только последнюю запись о приеме для каждого физлица. Для этого выполним следующие действия:
ФизическоеЛицо и найдем МАКСИМУМ(ДатаПриема).Пример структуры запроса:
ВЫБРАТЬ
ТекущиеКадровыеДанные.ФизическоеЛицо КАК ФизическоеЛицо,
МАКСИМУМ(ТекущиеКадровыеДанные.ДатаПриема) КАК МаксДатаПриема
ПОМЕСТИТЬ ВТ_ПоследниеДаты
ИЗ
РегистрСведений.ТекущиеКадровыеДанныеСотрудников КАК ТекущиеКадровыеДанные
СГРУППИРОВАТЬ ПО
ТекущиеКадровыеДанные.ФизическоеЛицо
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ПоследниеДаты.ФизическоеЛицо,
ТекущиеДанные.Должность,
ТекущиеДанные.Подразделение,
ВТ_ПоследниеДаты.МаксДатаПриема
ИЗ
ВТ_ПоследниеДаты КАК ВТ_ПоследниеДаты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ТекущиеКадровыеДанныеСотрудников КАК ТекущиеДанные
ПО ВТ_ПоследниеДаты.ФизическоеЛицо = ТекущиеДанные.ФизическоеЛицо
И ВТ_ПоследниеДаты.МаксДатаПриема = ТекущиеДанные.ДатаПриема
Такой подход гарантирует, что в выборку попадет ровно одна запись на человека — та, где дата приема самая поздняя. Это исключает необходимость фильтрации в коде 1С.
В современных версиях ЗУП 3.1 разработчики предусмотрели мощный инструмент для получения кадровых данных. Вместо того чтобы писать запросы к регистрам вручную (что чревато ошибками из-за специфики учета периодов), рекомендуется использовать функцию КадровыйУчет.КадровыеДанныеСотрудников.
Этот метод самостоятельно обрабатывает срезы последних, учитывает актуальность карточек сотрудников и возвращает готовую таблицу значений. Выясним причину, почему это лучше: типовая функция учитывает множество нюансов (например, работу по совместительству или исправление документов), которые сложно предусмотреть в самописном запросе.
Пример использования функции:
// Подготовим массив сотрудников (или физлиц)
СписокСотрудников = СформироватьМассивСотрудников(); // Ваша логика получения списка
// Опишем нужные нам поля через запятую
Поля = "ФизическоеЛицо,Подразделение,Должность,ДатаПриема,ДатаУвольнения,СтраховойНомерПФР";
// Вызываем типовой метод
ДанныеСотрудников = КадровыйУчет.КадровыеДанныеСотрудников(Ложь, СписокСотрудников, Поля, ТекущаяДата());
// На выходе получаем таблицу без лишних дублей истории
Для Каждого СтрокаДанных Из ДанныеСотрудников Цикл
// Сразу работаем с актуальными данными
КонецЦикла;
Использование КадровыйУчет — это «золотой стандарт» разработки под ЗУП 3.1, так как ваш код сохранит работоспособность даже после обновлений конфигурации.
Помимо удаления дублей, важно обратить внимание на корректность формирования самого файла CSV. В исходном сообщении темы было замечено, что данные просто соединяются через запятую ИспользуемыйРазделитель. Это опасно. Если в названии должности или подразделения встретится запятая (например, «Отдел маркетинга, рекламы и PR»), структура файла «поплывет», и Excel откроет его некорректно.
Правило формирования текстовых полей: всегда заключайте строковые данные в двойные кавычки и экранируйте внутренние кавычки. Рассмотрим пример правильной функции формирования строки:
Функция ПодготовитьПоле(Значение)
Текст = Строка(Значение);
// Заменяем одну кавычку на две (экранирование по стандарту RFC 4180)
Текст = СтрЗаменить(Текст, """", """""");
Возврат """" + Текст + """";
КонецФункции
// Применение:
СтрокаФайла = ПодготовитьПоле(СтрокаТЗ.ФизическоеЛицо) + "," + ПодготовитьПоле(СтрокаТЗ.Подразделение);
Для удаления дублей при выгрузке из 1С:ЗУП 3.1 мы проанализировали три основных подхода:
ТЗ.Сортировать().МАКСИМУМ.КадровыйУчет.КадровыеДанныеСотрудников является самым надежным и рекомендуемым для данной конфигурации.Выбор метода зависит от ваших задач, но помните, что качественный код должен не только выдавать правильный результат, но и быть устойчивым к изменениям данных в информационной базе.