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

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

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

Анализ типичной ошибки в запросе с агрегатными функциями

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

Посмотрим на пример ошибочного запроса:


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

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

Решение 1: Использование виртуальной таблицы «СрезПоследних»

В платформе 1С:Предприятие для периодических регистров сведений предусмотрена виртуальная таблица СрезПоследних. Она оптимизирована на уровне СУБД и автоматически рассчитывает актуальные данные на переданную дату среза.

Разберем по шагам, как правильно использовать эту таблицу:

  1. Передаем в первый параметр виртуальной таблицы граничную дату выборки (момент времени).
  2. Учитываем время среза. Если передать просто дату без указания времени (например, &ДатаКон = 31.12.2018 00:00:00), то все движения, сделанные в течение дня 31 декабря, не войдут в срез. Необходимо передавать конец дня через функцию КонецПериода(&ДатаКон, "ДЕНЬ") или использовать объект Граница с видом ВидГраницы.Включая.

Посмотрим на пример запроса со срезом последних:


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

Важный момент: виртуальная таблица среза срезает данные по системному полю Период регистра (или по позиции документа-регистратора), а не по пользовательским реквизитам ДатаНачала и ДатаКонец.

Решение 2: Получение последних записей через временные таблицы (ручной срез)

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

Разберем алгоритм построения пакетного запроса:

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

Рассмотрим пример правильного запроса с временной таблицей:


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

СГРУППИРОВАТЬ ПО
    ЕБКРс.ФГ,
    ЕБКРс.ФПГ,
    ЕБКРс.АБП,
    ЕБКРс.ПГ,
    ЕБКРс.ППГ

ИНДЕКСИРОВАТЬ ПО
    ФГ,
    ФПГ,
    АБП,
    ПГ,
    ППГ
;

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

Как избежать дублирования строк при одинаковых максимальных датах

Если в регистре сведений возможна ситуация, когда на одну и ту же максимальную дату для одной комбинации измерений приходится несколько записей (например, создано несколько документов в одну секунду), простое соединение по дате вернет дубли строк.

Для гарантированного устранения неоднозначности в ключ выборки среза добавляют системные поля Регистратор.МоментВремени (или Период) и НомерСтроки, находя максимум сначала по моменту времени документа, а затем при необходимости — по номеру строки.

← На главную