При разработке отчетов и обработок в 1С разработчики часто сталкиваются с задачей получения актуальных (последних) данных из периодического регистра сведений за определенный период или на конкретную дату. При решении этой задачи нередко возникают логические ошибки в запросах: запрос возвращает задвоенные данные, устаревшие строки или не отсекает предыдущие периоды. Рассмотрим подробно, почему возникают такие проблемы и как правильно строить выборку среза последних данных.
Проанализируем ситуацию, когда разработчик пытается вручную отобрать последние записи регистра без использования стандартной виртуальной таблицы среза. Типичная ошибка заключается в попытке сгруппировать данные по полям, которые делают каждую строку уникальной, например, по дате начала действия классификатора или интервала.
Посмотрим на пример ошибочного запроса:
ВЫБРАТЬ
ЕБКРс.ФГ КАК ФГ,
ЕБКРс.ФПГ КАК ФПГ,
ЕБКРс.АБП КАК АБП,
ЕБКРс.ПГ КАК ПГ,
ЕБКРс.ППГ КАК ППГ,
ЕБКРс.НаименованиеЭлементаРус КАК НаименованиеЭлементаРус,
ЕБКРс.НаименованиеЭлементаКаз КАК НаименованиеЭлементаКаз,
ЕБКРс.ДатаНачала КАК ДатаНачала,
МАКСИМУМ(ЕБКРс.ДатаКонец) КАК ДатаКонец
ИЗ
РегистрСведений.ЕБКРс КАК ЕБКРс
ГДЕ
ЕБКРс.ДатаКонец <= &ДатаКон
СГРУППИРОВАТЬ ПО
ЕБКРс.ФГ,
ЕБКРс.ФПГ,
ЕБКРс.АБП,
ЕБКРс.ПГ,
ЕБКРс.ППГ,
ЕБКРс.НаименованиеЭлементаРус,
ЕБКРс.НаименованиеЭлементаКаз,
ЕБКРс.ДатаНачала
Выясним причину некорректной работы такого запроса. В секции СГРУППИРОВАТЬ ПО присутствует поле ЕБКРс.ДатаНачала. Если для одной и той же аналитики в 2017 году была дата начала 01.01.2017, а в 2018 году — 01.01.2018, СУБД сгруппирует записи отдельно по каждому значению даты начала. В результате функция МАКСИМУМ(ЕБКРс.ДатаКонец) посчитает максимум внутри каждой группы (по каждой дате начала отдельно), и старые записи за 2017 год не отбросятся.
В платформе 1С:Предприятие для периодических регистров сведений предусмотрена виртуальная таблица СрезПоследних. Она оптимизирована на уровне СУБД и автоматически рассчитывает актуальные данные на переданную дату среза.
Разберем по шагам, как правильно использовать эту таблицу:
&ДатаКон = 31.12.2018 00:00:00), то все движения, сделанные в течение дня 31 декабря, не войдут в срез. Необходимо передавать конец дня через функцию КонецПериода(&ДатаКон, "ДЕНЬ") или использовать объект Граница с видом ВидГраницы.Включая.Посмотрим на пример запроса со срезом последних:
ВЫБРАТЬ
ЕБКРс.ФГ КАК ФГ,
ЕБКРс.ФПГ КАК ФПГ,
ЕБКРс.АБП КАК АБП,
ЕБКРс.ПГ КАК ПГ,
ЕБКРс.ППГ КАК ППГ,
ЕБКРс.НаименованиеЭлементаРус КАК НаименованиеЭлементаРус,
ЕБКРс.НаименованиеЭлементаКаз КАК НаименованиеЭлементаКаз,
ЕБКРс.ДатаНачала КАК ДатаНачала,
ЕБКРс.ДатаКонец КАК ДатаКонец,
ЕБКРс.Регистратор КАК Регистратор
ИЗ
РегистрСведений.ЕБКРс.СрезПоследних(&ПериодСреза, ) КАК ЕБКРс
Важный момент: виртуальная таблица среза срезает данные по системному полю Период регистра (или по позиции документа-регистратора), а не по пользовательским реквизитам ДатаНачала и ДатаКонец.
Если специфика задачи требует получения среза не по системному периоду, а по реквизиту даты окончания действия, либо требуется избежать использования виртуальных таблиц на непериодических регистрах, задачу решают в два шага через пакетный запрос.
Разберем алгоритм построения пакетного запроса:
МАКСИМУМ(ДатаКонец) с фильтром по верхней границе. В секцию СГРУППИРОВАТЬ ПО помещаем только ключевые измерения. Никаких дополнительных дат или реквизитов включать в группировку нельзя.ВНУТРЕННЕЕ СОЕДИНЕНИЕ по ключевым измерениям и по совпадению даты с вычисленным максимумом.Рассмотрим пример правильного запроса с временной таблицей:
ВЫБРАТЬ
ЕБКРс.ФГ КАК ФГ,
ЕБКРс.ФПГ КАК ФПГ,
ЕБКРс.АБП КАК АБП,
ЕБКРс.ПГ КАК ПГ,
ЕБКРс.ППГ КАК ППГ,
МАКСИМУМ(ЕБКРс.ДатаКонец) КАК МаксДатаКонец
ПОМЕСТИТЬ втМаксимумы
ИЗ
РегистрСведений.ЕБКРс КАК ЕБКРс
ГДЕ
ЕБКРс.ДатаКонец <= &ДатаКон
И ЕБКРс.ДатаКонец >= &ДатаНач
СГРУППИРОВАТЬ ПО
ЕБКРс.ФГ,
ЕБКРс.ФПГ,
ЕБКРс.АБП,
ЕБКРс.ПГ,
ЕБКРс.ППГ
ИНДЕКСИРОВАТЬ ПО
ФГ,
ФПГ,
АБП,
ПГ,
ППГ
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ЕБКРс.ФГ КАК ФГ,
ЕБКРс.ФПГ КАК ФПГ,
ЕБКРс.АБП КАК АБП,
ЕБКРс.ПГ КАК ПГ,
ЕБКРс.ППГ КАК ППГ,
ЕБКРс.НаименованиеЭлементаРус КАК НаименованиеЭлементаРус,
ЕБКРс.НаименованиеЭлементаКаз КАК НаименованиеЭлементаКаз,
ЕБКРс.ДатаНачала КАК ДатаНачала,
ЕБКРс.ДатаКонец КАК ДатаКонец
ИЗ
втМаксимумы КАК втМаксимумы
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЕБКРс КАК ЕБКРс
ПО втМаксимумы.ФГ = ЕБКРс.ФГ
И втМаксимумы.ФПГ = ЕБКРс.ФПГ
И втМаксимумы.АБП = ЕБКРс.АБП
И втМаксимумы.ПГ = ЕБКРс.ПГ
И втМаксимумы.ППГ = ЕБКРс.ППГ
И втМаксимумы.МаксДатаКонец = ЕБКРс.ДатаКонец
Если в регистре сведений возможна ситуация, когда на одну и ту же максимальную дату для одной комбинации измерений приходится несколько записей (например, создано несколько документов в одну секунду), простое соединение по дате вернет дубли строк.
Для гарантированного устранения неоднозначности в ключ выборки среза добавляют системные поля Регистратор.МоментВремени (или Период) и НомерСтроки, находя максимум сначала по моменту времени документа, а затем при необходимости — по номеру строки.