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

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

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

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

Метод 1. Классический подход с использованием временных таблиц

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

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

Проанализируем пример кода:


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

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


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

Этот метод считается стандартом де-факто, так как он позволяет СУБД эффективно использовать индексы. Обратите внимание, что если поле Дата в непериодическом регистре не является измерением, крайне желательно установить для него флаг «Индексировать» в конфигураторе для ускорения работы запроса.

Метод 2. Решение проблемы дублей (коллизия дат)

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

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

  1. Использование дополнительных полей: Если в регистре есть поле НомерСтроки, МоментВремени или уникальный идентификатор, при поиске максимума во временной таблице нужно выбирать МАКСИМУМ не только по дате, но и по этому уникальному полю.
  2. Группировка результата: Если дополнительных полей нет, нам придется «схлопнуть» дублирующие записи в финальном запросе, применив к ресурсам агрегатные функции, такие как МАКСИМУМ или СУММА, в зависимости от бизнес-логики.

Метод 3. Использование оконных функций (Платформа 8.3.20+)

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

Разберем, как выглядит такой запрос:


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

ВЫБРАТЬ
    *
ИЗ
    ВТ_ПронумерованныеДанные
ГДЕ
    НомерЗаписи = 1;

Преимущества этого метода:

Архитектурные рекомендации

Проанализируем ситуацию с точки зрения проектирования системы. Если вы обнаружили, что вам постоянно требуется «срез последних» по непериодическому регистру, это может сигнализировать об ошибке в выборе типа объекта.

Что можно сделать:

  1. Сделать регистр периодическим. Если бизнес-логика подразумевает хранение истории изменений во времени, это самое правильное решение. Вы получите готовую виртуальную таблицу и автоматическую индексацию по периоду.
  2. Создать вспомогательный регистр «Текущие значения». Если основной регистр слишком велик и хранит детальную историю, для ускорения отчетов можно создать второй непериодический регистр, в котором будет храниться только одна (актуальная) запись для каждой ключевой сущности. Этот регистр должен обновляться программно при записи в основной регистр истории.

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

← На главную