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

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

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

Особенности работы виртуальной таблицы «СрезПоследних»

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

  1. Механизм группировки СУБД: Виртуальная таблица СрезПоследних на уровне СУБД всегда формирует срез в разрезе абсолютно всех измерений, объявленных в структуре регистра.
  2. Назначение параметров ВТ: Передача условия (например, Договор = &Договор) в параметры виртуальной таблицы лишь фильтрует исходные записи, но не отменяет группировку по остальным измерениям (Организация, Контрагент). Если в базе по этому договору есть записи с разными организациями, виртуальная таблица вернет актуальную запись для каждой пары «Организация + Договор».

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

Способ 1. Пакетный запрос с временной таблицей (Рекомендуемый метод)

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

Разберем решение по шагам:

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

Посмотрим на пример 구현 такого запроса:


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

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

Защита от дублей при совпадении периода (коллизии по времени)

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

Чтобы гарантировать выбор строго одной актуальной записи, разберем добавление дополнительного критерия уникальности во временную таблицу — максимального номера строки или регистратора:


ВЫБРАТЬ
    Регистр.Договор КАК Договор,
    МАКСИМУМ(Регистр.Период) КАК Период,
    МАКСИМУМ(Регистр.НомерСтроки) КАК НомерСтроки
ПОМЕСТИТЬ ВТ_ТочныйСрез
ИЗ
    РегистрСведений.НашРегистр КАК Регистр
ГРУППИРОВАТЬ ПО
    Регистр.Договор
;

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

Способ 2. Использование подзапроса с оператором «В»

Рассмотрим альтернативный вариант без явного использования временных таблиц через коррелированный запрос с конструкцией ГДЕ (Измерение, Период) В (...). Этот способ удобен для простых отчетов или вложенных схем:


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

Архитектурные рекомендации по проектированию регистров

Проанализируем структуру метаданных. Если в процессе разработки выясняется, что срез сведений регулярно требуется получать строго в разрезе одного поля (например, Договор), а остальные поля (Организация, Контрагент) хранят лишь сопутствующую аналитику на момент записи, то следует оценить корректность структуры регистра:

← На главную