При работе с периодическими регистрами сведений разработчики часто сталкиваются с ситуацией, когда обращение к виртуальной таблице СрезПоследних возвращает сразу несколько строк по объекту, хотя ожидается только одна — самая свежая по дате. Рассмотрим подробнее, почему так происходит, как устроена механика работы среза в платформе 1С:Предприятие и какими способами можно гарантированно получить строго последнюю запись.
Разберем внутреннюю логику платформы. Согласно спецификации, метод и виртуальная таблица СрезПоследних получают наиболее поздние записи регистра для каждого уникального сочетания всех имеющихся измерений.
Если в регистре сведений созданы два измерения — например, Зона и Физлицо, — то ключом уникальности записи выступает пара Период + Зона + Физлицо. Когда для одной зоны в разные периоды времени привязываются разные физические лица, каждое такое сочетание измерений образует самостоятельную цепочку значений. В результате виртуальная таблица СрезПоследних вернет срез для каждой пары (Зона1, Физлицо1) и (Зона1, Физлицо2), то есть обе записи попадут в выборку.
Для решения этой задачи существует несколько подходов в зависимости от того, есть ли возможность изменять метаданные конфигурации или требуется решить задачу исключительно на уровне запроса.
Проанализируем структуру регистра в дереве метаданных конфигуратора. Если по бизнес-логике в один момент времени за одной зоной (или сотрудником) может быть закреплено строго одно физическое лицо, поле Физлицо не должно являться измерением.
Выполним следующие действия:
Физлицо из ветки Измерения в ветку Ресурсы.Зона.После этого срез последних будет формироваться исключительно в разрезе измерений (полю Зона), а в ресурсе Физлицо платформа автоматически вернет актуальное значение на указанную дату среза.
Текст запроса в этом случае становится предельно простым:
ВЫБРАТЬ
Срез.Зона КАК Зона,
Срез.Физлицо КАК Физлицо,
Срез.Период КАК Период
ИЗ
РегистрСведений.ФизЛицаЗоныПоПериоду.СрезПоследних(&Период, ) КАК Срез
Если менять структуру регистра нельзя (например, конфигурация находится на поддержке без возможности редактирования или сочетание измерений оправдано бизнес-логикой), решим задачу средствами языка запросов.
Разберем по шагам алгоритм получения среза:
Зона) из реальной таблицы регистра.Посмотрим на пример оптимального запроса:
ВЫБРАТЬ
Таблица.Зона КАК Зона,
МАКСИМУМ(Таблица.Период) КАК Период
ПОМЕСТИТЬ ВТ_МаксимальныеПериоды
ИЗ
РегистрСведений.ФизЛицаЗоныПоПериоду КАК Таблица
СГРУППИРОВАТЬ ПО
Таблица.Зона
ИНДЕКСИРОВАТЬ ПО
Зона,
Период
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ.Зона КАК Зона,
Регистр.Физлицо КАК Физлицо,
ВТ.Период КАК Период
ИЗ
ВТ_МаксимальныеПериоды КАК ВТ
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ФизЛицаЗоныПоПериоду КАК Регистр
ПО ВТ.Зона = Регистр.Зона
И ВТ.Период = Регистр.Период
Важный нюанс: если в регистре возможны ситуации, когда на одну и ту же секунду (или дату) по одной зоне введены две записи с разными физическими лицами, простое соединение по периоду вернет дубли строк. Чтобы избежать неоднозначности, в группировку и условие связи рекомендуется дополнительно включать поле НомерСтроки (а для регистра с режимом подчинения регистратору — Регистратор).
В современных версиях платформы 1С:Предприятие задачу нумерации и фильтрации последних записей удобно решать с помощью оконной функции ROW_NUMBER() без необходимости выполнения группировок и повторных соединений таблиц.
Рассмотрим пример реализации:
ВЫБРАТЬ
ВложенныйЗапрос.Зона КАК Зона,
ВложенныйЗапрос.Физлицо КАК Физлицо,
ВложенныйЗапрос.Период КАК Период
ИЗ
(ВЫБРАТЬ
Таблица.Зона КАК Зона,
Таблица.Физлицо КАК Физлицо,
Таблица.Период КАК Период,
ROW_NUMBER() OVER(
PARTITION BY Таблица.Зона
ORDER BY Таблица.Период УБЫВ, Таблица.НомерСтроки УБЫВ
) КАК НомерСтрокиЗаписи
ИЗ
РегистрСведений.ФизЛицаЗоныПоПериоду КАК Таблица) КАК ВложенныйЗапрос
ГДЕ
ВложенныйЗапрос.НомерСтрокиЗаписи = 1
Оконная функция разбивает выборку на секции по измерению Зона, упорядочивает записи внутри каждой секции по убыванию даты и присваивает первой (самой последней по времени) записи номер 1.
Если отчет строится в СКД, можно обойтись без громоздких конструкций в тексте запроса, используя механизм связей наборов данных:
ВЫБРАТЬ РАЗЛИЧНЫЕ Зона ИЗ ...).РегистрСведений.ФизЛицаЗоныПоПериоду.СрезПоследних(, Зона = &Зона).НаборДанных1 (источник) с НаборДанных2 (приемник) по полю Зона, передав значение в параметр Зона.При таком подходе СКД сформирует параметризованный срез индивидуально для каждой зоны, что обеспечит корректность выборки и высокую производительность отчета.