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

Программист 1С v8.3 (Обычные формы)
← На главную

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

В чем заключается проблема «Среза последних»?

Разберем ситуацию на примере регистра ОсновныеСпецификацииНоменклатуры. В нем есть измерения Номенклатура и Подразделение. Если мы используем стандартную виртуальную таблицу СрезПоследних, система возвращает актуальные данные в разрезе уникальных комбинаций всех измерений. Это фундаментальный принцип работы регистров сведений.

Проанализируем пример данных:

  1. 01.01.2019 — Калоши — Подразделение 1
  2. 02.02.2019 — Калоши — Подразделение 2

Если мы обратимся к таблице СрезПоследних, запрос вернет обе строки. Почему? Потому что комбинация «Калоши + Подразделение 1» и «Калоши + Подразделение 2» уникальна для системы. Платформа считает, что это две разные ветки истории. Но если наша задача — узнать, в каком подразделении калоши числились в последний раз, нам нужна только вторая строка. В этом случае стандартный СрезПоследних нам не поможет.

Решение проблемы через запрос с использованием МАКСИМУМ(Период)

Для того чтобы получить действительно последнюю запись по конкретной номенклатуре, независимо от того, какие еще измерения указаны в регистре, мы должны применить классический метод «двух шагов» в одном запросе. Рассмотрим этот алгоритм подробнее.

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

Проанализируем пример кода запроса, который решает эту задачу:


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

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

Разберем, что происходит в этом запросе по шагам:

  1. В первом пакете мы обращаемся к физической таблице регистра. Мы группируем записи по измерению Номенклатура и выбираем функцию МАКСИМУМ(Период). Это дает нам список пар «Номенклатура — дата самой последней записи». Мы сохраняем этот результат во временную таблицу для оптимизации.
  2. Во втором пакете мы берем нашу временную таблицу и «подклеиваем» к ней данные из того же регистра. Соединение идет по двум полям: Номенклатура и Период.
  3. В результате система находит строку, которая соответствует самой поздней дате для конкретной номенклатуры, и вытягивает из этой строки нужное нам значение измерения Подразделение.

Важные нюансы и «подводные камни»

Выясним причину, по которой этот метод может иногда выдавать «лишние» записи. Если в одну и ту же секунду (период) по одной и той же номенклатуре будет сделано две записи с разными подразделениями, наш запрос вернет обе. Это происходит потому, что поле Период перестает быть уникальным идентификатором записи в рамках секунды.

Чтобы избежать такой ситуации, профессиональные разработчики рекомендуют:

Также стоит проанализировать структуру самого регистра. Если бизнес-логика задачи подразумевает, что у номенклатуры всегда может быть только одно актуальное подразделение, то архитектурно правильнее сделать «Подразделение» ресурсом, а не измерением. В этом случае обычная виртуальная таблица СрезПоследних по номенклатуре сразу будет возвращать одну нужную строку.

Оптимизация производительности

Рассмотрим вопрос скорости работы запроса на больших объемах данных. Обращение к физической таблице с группировкой — операция ресурсоемкая. Чтобы отчет работал быстро, убедитесь в следующем:

  1. Измерение Номенклатура проиндексировано. В 1С это происходит автоматически, если измерение является «Ведущим» или у него включено индексирование.
  2. Во временной таблице ВременнаяТаблицаМаксДаты желательно создать индекс по полям связи (номенклатура и период), особенно если номенклатур в выборке много.
  3. Если вам нужно получить данные не по всему справочнику, а по конкретному списку товаров, обязательно наложите условие ГДЕ уже в первом запросе пакета (где мы ищем максимум периода).

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

← На главную