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

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

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

Разбор типичной ошибки: почему группировка по всем полям не работает

Часто начинающие разработчики пытаются получить максимальную дату, просто добавив функцию МАКСИМУМ к нужному полю и перечислив все остальные поля в секции СГРУППИРОВАТЬ ПО. Проанализируем, почему это приводит к неверному результату. Если мы напишем запрос следующим образом:


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

Проблема заключается в том, что СУБД будет искать уникальные комбинации всех полей, указанных в группировке. Если у Иванова есть старый паспорт (серия 1111) и новый (серия 2222), то эти записи образуют разные группы. В итоге запрос вернет обе записи, так как их серии различаются. Функция МАКСИМУМ сработает только внутри этих групп, что в данном случае бесполезно.

Решение через вложенный запрос и соединение

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

Шаг 1. Получение максимальных дат. Создадим вложенную таблицу, где для каждого ключевого поля (измерения) будет определено одно максимальное значение искомого ресурса.


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

Шаг 2. Соединение с основной таблицей. Теперь мы выбираем все необходимые поля из регистра, соединяя его с нашей временной таблицей по двум полям: по объекту (Физлицо) и по значению, которое мы максимизировали (ДатаВыдачи).


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

Такой подход гарантирует, что мы получим только те строки, где дата совпадает с максимальной для данного человека. Рассмотрим ситуацию, если у одного человека есть два разных документа с абсолютно одинаковой датой выдачи. В этом случае запрос вернет две строки. Чтобы этого избежать, можно добавить дополнительные условия в группировку (например, по виду документа) или использовать ключевое слово РАЗЛИЧНЫЕ, если дубликаты идентичны.

Использование виртуальной таблицы СрезПоследних

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

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


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

Однако, если задача стоит именно в поиске максимального значения ресурса ДатаВыдачи, метод с соединением через МАКСИМУМ является единственно верным.

Важные замечания по работе с виртуальными полями

При написании запросов следует помнить о поле Представление. Как мы увидели в обсуждении, попытка группировки по этому полю вызывает ошибку. Проанализируем ситуацию: Представление — это виртуальное поле, формируемое платформой 1С динамически для отображения ссылки в удобном для человека виде. Его нельзя использовать в секциях СГРУППИРОВАТЬ ПО, ГДЕ или в условиях соединения. Всегда используйте реальные поля базы данных (например, Ссылка, Код, Наименование или измерения регистра).

Оптимизация производительности

Для ускорения работы запроса на больших объемах данных рекомендуется:

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

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

← На главную