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