Как убрать дубли сотрудников при выгрузке в CSV или Excel из 1С:ЗУП 3.1

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

При разработке отчетов или обработок выгрузки в конфигурации 1С:Зарплата и Управление Персоналом 3.1 программисты часто сталкиваются с проблемой дублирования строк. Типичная ситуация: сотрудник увольнялся и принимался на работу снова. В регистрах сведений 1С по такому человеку хранится несколько записей, и обычный запрос к срезу последних или кадровой истории может вернуть обе строки. Если нам нужна только актуальная информация (последнее место работы), лишние данные необходимо отсечь.

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

Причина возникновения дублей

Прежде чем исправлять код, проанализируем ситуацию. В ЗУП 3.1 понятия ФизическоеЛицо и Сотрудник разделены. Одно физлицо может иметь несколько карточек сотрудников (основное место работы, внутреннее совместительство, или новая карточка после увольнения). Если в запросе соединение идет по полю ФизическоеЛицо, система честно выбирает все связанные записи. Наша задача — оставить только ту запись, которая является наиболее актуальной на текущий момент.

Решение 1: Фильтрация при обходе таблицы значений

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

Рассмотрим по шагам, как модифицировать алгоритм:

  1. Сортируем таблицу значений по ФизическоеЛицо и по убыванию ДатаПриема. Таким образом, самая свежая запись по каждому человеку окажется первой в списке.
  2. Вводим переменную для хранения идентификатора предыдущего обработанного физлица.
  3. В цикле сравниваем текущее физлицо с предыдущим. Если они совпадают — пропускаем итерацию.

Посмотрим на пример кода:


// Сначала сортируем таблицу, чтобы актуальные записи были сверху
ТЗ.Сортировать("ФизическоеЛицо Возр, ДатаПриема Убыв");

ПоследнееФизЛицо = Неопределено;
ТекстCSV = "";

Для Каждого СтрокаТЗ Из ТЗ Цикл
    // Если это тот же человек, что и в прошлой строке - игнорируем
    Если СтрокаТЗ.ФизическоеЛицо = ПоследнееФизЛицо Тогда
        Продолжить;
    КонецЕсли;

    // Запоминаем текущее лицо как последнее обработанное
    ПоследнееФизЛицо = СтрокаТЗ.ФизическоеЛицо;

    // Формируем строку CSV
    ТекстCSV = ТекстCSV + СтрокаТЗ.ФизическоеЛицоФамилия + "," + СтрокаТЗ.Должность + Символы.ПС;
КонецЦикла;

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

Решение 2: Оптимизация запроса через временные таблицы

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

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

  1. Создадим временную таблицу, где сгруппируем данные по ФизическоеЛицо и найдем МАКСИМУМ(ДатаПриема).
  2. Соединим эту временную таблицу с основной выборкой по двум полям одновременно: по физлицу и по дате приема.

Пример структуры запроса:


ВЫБРАТЬ
    ТекущиеКадровыеДанные.ФизическоеЛицо КАК ФизическоеЛицо,
    МАКСИМУМ(ТекущиеКадровыеДанные.ДатаПриема) КАК МаксДатаПриема
ПОМЕСТИТЬ ВТ_ПоследниеДаты
ИЗ
    РегистрСведений.ТекущиеКадровыеДанныеСотрудников КАК ТекущиеКадровыеДанные
СГРУППИРОВАТЬ ПО
    ТекущиеКадровыеДанные.ФизическоеЛицо
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_ПоследниеДаты.ФизическоеЛицо,
    ТекущиеДанные.Должность,
    ТекущиеДанные.Подразделение,
    ВТ_ПоследниеДаты.МаксДатаПриема
ИЗ
    ВТ_ПоследниеДаты КАК ВТ_ПоследниеДаты
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ТекущиеКадровыеДанныеСотрудников КАК ТекущиеДанные
    ПО ВТ_ПоследниеДаты.ФизическоеЛицо = ТекущиеДанные.ФизическоеЛицо
    И ВТ_ПоследниеДаты.МаксДатаПриема = ТекущиеДанные.ДатаПриема

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

Решение 3: Использование типового программного интерфейса ЗУП

В современных версиях ЗУП 3.1 разработчики предусмотрели мощный инструмент для получения кадровых данных. Вместо того чтобы писать запросы к регистрам вручную (что чревато ошибками из-за специфики учета периодов), рекомендуется использовать функцию КадровыйУчет.КадровыеДанныеСотрудников.

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

Пример использования функции:


// Подготовим массив сотрудников (или физлиц)
СписокСотрудников = СформироватьМассивСотрудников(); // Ваша логика получения списка

// Опишем нужные нам поля через запятую
Поля = "ФизическоеЛицо,Подразделение,Должность,ДатаПриема,ДатаУвольнения,СтраховойНомерПФР";

// Вызываем типовой метод
ДанныеСотрудников = КадровыйУчет.КадровыеДанныеСотрудников(Ложь, СписокСотрудников, Поля, ТекущаяДата());

// На выходе получаем таблицу без лишних дублей истории
Для Каждого СтрокаДанных Из ДанныеСотрудников Цикл
    // Сразу работаем с актуальными данными
КонецЦикла;

Использование КадровыйУчет — это «золотой стандарт» разработки под ЗУП 3.1, так как ваш код сохранит работоспособность даже после обновлений конфигурации.

Нюансы формата CSV: кавычки и запятые

Помимо удаления дублей, важно обратить внимание на корректность формирования самого файла CSV. В исходном сообщении темы было замечено, что данные просто соединяются через запятую ИспользуемыйРазделитель. Это опасно. Если в названии должности или подразделения встретится запятая (например, «Отдел маркетинга, рекламы и PR»), структура файла «поплывет», и Excel откроет его некорректно.

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


Функция ПодготовитьПоле(Значение)
    Текст = Строка(Значение);
    // Заменяем одну кавычку на две (экранирование по стандарту RFC 4180)
    Текст = СтрЗаменить(Текст, """", """""");
    Возврат """" + Текст + """";
КонецФункции

// Применение:
СтрокаФайла = ПодготовитьПоле(СтрокаТЗ.ФизическоеЛицо) + "," + ПодготовитьПоле(СтрокаТЗ.Подразделение);

Подведем итоги

Для удаления дублей при выгрузке из 1С:ЗУП 3.1 мы проанализировали три основных подхода:

  1. Программный обход с проверкой: подходит для простых задач, требует предварительной сортировки ТЗ.Сортировать().
  2. Временные таблицы в запросе: наиболее производительный метод, использующий агрегатные функции МАКСИМУМ.
  3. Типовые функции: метод КадровыйУчет.КадровыеДанныеСотрудников является самым надежным и рекомендуемым для данной конфигурации.

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

← На главную