Как получить только один последний документ физического лица в запросе 1С

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

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

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

Почему СрезПоследних возвращает несколько записей

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

То для одного человека, у которого в базе зарегистрированы паспорт РФ и водительское удостоверение, СрезПоследних вернет две строки. Платформа честно покажет последнее состояние по паспорту и последнее состояние по водительскому удостоверению. Но если наша цель — получить одно-единственное действующее удостоверение личности, стандартный простой запрос к виртуальной таблице вернет избыточные данные.

Давайте рассмотрим несколько способов решения этой задачи в зависимости от контекста вашей разработки.

Решение 1: Выборка первого документа с сортировкой по дате (для одного физлица)

Если перед нами стоит задача быстро получить актуальный документ для одного конкретного физического лица (например, при печати договора или приказа из карточки сотрудника), мы можем использовать конструкцию ВЫБРАТЬ ПЕРВЫЕ 1 в сочетании с сортировкой по убыванию даты или периода.

Разберем по шагам этот запрос:


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

Важный нюанс: Обязательно используйте упорядочивание (УПОРЯДОЧИТЬ ПО). Без него платформа вернет случайную запись из таблицы результатов. Мы выполняем сортировку по полю Период (дата внесения записи в регистр) и ДатаВыдачи в обратном порядке (УБЫВ), чтобы на самый верх списка попал наиболее свежий документ.

Решение 2: Фильтрация по признаку основного документа удостоверения личности

Если вы работаете в типовых конфигурациях 1С (таких как ЗУП 3, ERP 2.0 или Комплексная автоматизация), то структура регистра ДокументыФизическихЛиц содержит предопределенный механизм для решения этой проблемы. В системе присутствует реквизит (или ресурс) ЯвляетсяДокументомУдостоверяющимЛичность с типом Булево.

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

Используем этот признак в параметрах виртуальной таблицы:


ВЫБРАТЬ
    Документы.Физлицо КАК Физлицо,
    Документы.Серия КАК Серия,
    Документы.Номер КАК Номер,
    Документы.ДатаВыдачи КАК ДатаВыдачи,
    Документы.ВидДокумента КАК ВидДокумента
ИЗ
    РегистрСведений.ДокументыФизическихЛиц.СрезПоследних(&ДатаСреза, 
        Физлицо = &Физлицо 
        И ЯвляетсяДокументомУдостоверяющимЛичность = ИСТИНА
    ) КАК Документы

Этот метод идеален, так как он работает мгновенно, не требует сложных соединений и гарантирует получение именно основного документа (паспорта, вида на жительство или паспорта иностранного гражданина), отсекая второстепенные документы (справки, пропуска, военные билеты).

Решение 3: Использование таблицы приоритетов документов (для списков сотрудников)

Что делать, если вам нужно построить отчет по списку из сотен сотрудников, у которых могут быть самые разные документы, и простое ограничение ВЫБРАТЬ ПЕРВЫЕ 1 использовать нельзя (так как оно обрежет весь список до одного человека)?

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

  1. Создадим временную таблицу приоритетов, где для каждого вида документа укажем его важность (например: Паспорт РФ — приоритет 1, Вид на жительство — приоритет 2, Загранпаспорт — приоритет 3).
  2. Соединим эту таблицу с результатом среза последних по регистру сведений.
  3. Сгруппируем результат по каждому физическому лицу, найдем минимальное значение приоритета.
  4. Повторным соединением выберем поля документа, соответствующие этому минимальному приоритету.

Проанализируем пример реализации этого механизма в запросе:


// Шаг 1: Создаем таблицу приоритетов в запросе
ВЫБРАТЬ
    ЗНАЧЕНИЕ(Справочник.ВидыДокументовФизическихЛиц.ПаспортРФ) КАК ВидДокумента,
    1 КАК Приоритет
ПОМЕСТИТЬ ВТ_Приоритеты

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ЗНАЧЕНИЕ(Справочник.ВидыДокументовФизическихЛиц.ВидНаЖительство),
    2
;

////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Получаем все последние документы сотрудников с их приоритетами
ВЫБРАТЬ
    Срез.Физлицо КАК Физлицо,
    Срез.ВидДокумента КАК ВидДокумента,
    ЕСТЬNULL(ВТ_Приоритеты.Приоритет, 99) КАК Приоритет,
    Срез.Серия КАК Серия,
    Срез.Номер КАК Номер,
    Срез.ДатаВыдачи КАК ДатаВыдачи
ПОМЕСТИТЬ ВТ_ВсеДокументы
ИЗ
    РегистрСведений.ДокументыФизическихЛиц.СрезПоследних(&ДатаСреза, ) КАК Срез
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Приоритеты КАК ВТ_Приоритеты
        ПО Срез.ВидДокумента = ВТ_Приоритеты.ВидДокумента
;

////////////////////////////////////////////////////////////////////////////////
// Шаг 3: Вычисляем лучший (минимальный) приоритет для каждого физлица
ВЫБРАТЬ
    ВТ_ВсеДокументы.Физлицо КАК Физлицо,
    МИНИМУМ(ВТ_ВсеДокументы.Приоритет) КАК МинимальныйПриоритет
ПОМЕСТИТЬ ВТ_МинимальныеПриоритеты
ИЗ
    ВТ_ВсеДокументы КАК ВТ_ВсеДокументы
ГРУППИРОВАТЬ ПО
    ВТ_ВсеДокументы.Физлицо
;

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

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

Решение 4: Использование готового программного интерфейса БСП (Рекомендуется)

Если вы ведете разработку внутри современных типовых конфигураций (ЗУП 3.1, ERP, КА, УТ), настоятельно рекомендуем отказаться от написания прямых запросов к регистру ДокументыФизическихЛиц. Структура метаданных в любой момент может измениться разработчиками фирмы «1С» (например, логику хранения истории документов могут оптимизировать или перенести в другие сущности).

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


// Формируем список сотрудников, по которым нужны данные
СписокФизЛиц = Новый Массив;
СписокФизЛиц.Добавить(ТекущееФизЛицо);

// Задаем список необходимых нам кадровых полей
КадровыеДанные = "ДокументВид, ДокументСерия, ДокументНомер, ДокументДатаВыдачи, ДокументПредставление";

// Вызываем программный интерфейс БСП
ТаблицаДанных = КадровыйУчет.КадровыеДанныеФизическихЛиц(Истина, СписокФизЛиц, КадровыеДанные, ТекущаяДата);

Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
    Сообщить("Документ: " + СтрокаДанных.ДокументПредставление);
КонецЦикла;

Преимущества работы через БСП:

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

← На главную