Как в запросе 1С 8.3 получить только последний документ сотрудника, если СрезПоследних выдает несколько строк?

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

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

Разбор проблемы: почему СрезПоследних выдает «дубли»

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

Для решения нам потребуется обойти это ограничение и найти самую последнюю дату (период) среди всех документов сотрудника, независимо от их вида. Рассмотрим этот процесс по шагам.

Шаг 1: Получение максимального периода во временную таблицу

Первым делом нам необходимо выяснить, какая дата записи является последней для каждого конкретного физического лица. Использовать виртуальную таблицу здесь не совсем удобно, поэтому мы обратимся к реальной (физической) таблице регистра сведений. Создадим временную таблицу, которую назовем ВТ_МаксимальныеПериоды.

Рассмотрим структуру этого запроса:


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

В данном фрагменте мы используем агрегатную функцию МАКСИМУМ для поля Период и группируем результат по Физлицо. Очень важно накладывать фильтр в секции ГДЕ, чтобы не пересчитывать данные по всей базе, а ограничиваться только нужным списком людей. Это критически важно для производительности системы.

Шаг 2: Получение данных конкретного документа

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

Важное замечание: если в одну и ту же секунду (период) по одному физическому лицу было введено две разные записи, система вернет две строки. Чтобы этого избежать, в итоговой выборке также рекомендуется использовать группировку или функцию МАКСИМУМ для вида документа.


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

СГРУППИРОВАТЬ ПО
    СотрудникиСрез.ФизЛицо,
    ВТ_МаксимальныеПериоды.МаксПериод,
    ФизЛица.Наименование

Почему нельзя просто использовать МАКСИМУМ в одном запросе?

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

Именно поэтому мы сначала находим пару (Физлицо + Период), а потом жестким соединением находим конкретную запись, которой соответствует этот период.

Оптимизация: отказ от обращений «через точку»

Обратите внимание на поле ФизЛица.Наименование. В исходном обсуждении предлагалось использовать конструкцию СотрудникиОрганизацииСрезПоследних.ФизЛицо.Наименование. Рассмотрим, почему это считается плохим тоном в разработке на 1С:

  1. Неявные соединения: Каждая точка в запросе порождает скрытое соединение LEFT JOIN на уровне СУБД. Если таких точек много, запрос начинает сильно тормозить.
  2. Отсутствие контроля: Вы не можете управлять типом соединения.
  3. Чтение лишних данных: Платформа может извлекать больше данных из таблиц, чем требуется для вывода одного поля.

Правильный путь — явное соединение со справочником ФизическиеЛица, как показано в примере выше. Это делает код прозрачным и предсказуемым для оптимизатора запросов SQL.

Итоговый алгоритм решения

Подведем итог. Чтобы получить последний документ, выполним следующие действия:

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

Такой подход гарантирует получение одной актуальной записи для каждого человека и обеспечивает высокую скорость работы даже на больших объемах данных в крупных организациях.

← На главную