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

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

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

В этой статье мы подробно разберем, как построить эффективный запрос, который позволит вычленить дату изменения именно интересующего нас ресурса, рассмотрим подводные камни производительности и обсудим современные методы решения этой задачи.

Постановка задачи и анализ проблемы

Представим регистр сведений (например, «Цены и остатки»), где есть измерения Номенклатура и Склад, и ресурсы Цена (Ресурс 1) и Количество (Ресурс 2). Нам нужно получить текущую цену и текущее количество, но в поле «Дата изменения» должна стоять дата именно последнего изменения цены. Если вчера изменилось только количество, а цена не менялась с прошлого месяца, запрос должен вернуть дату из прошлого месяца.

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

Решение 1: Классический алгоритм с использованием временных таблиц

Рассмотрим наиболее надежный алгоритм, который работает на всех версиях платформы 1С 8.x. Суть метода заключается в том, чтобы сначала определить актуальные значения ресурсов, а затем найти минимальный период для этого конкретного значения в непрерывной последовательности записей.

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

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

Посмотрим на пример кода, реализующий эту логику:


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

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

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

Нюанс «мерцающих» значений (Islands Problem)

Проанализируем ситуацию глубже. Если ресурс принимал значение 10 в январе, потом 20 в феврале, и снова 10 в марте, то вышеуказанный запрос с использованием МИНИМУМ(Период) вернет нам январь. Однако с точки зрения бизнеса нас чаще интересует март — момент, когда установилось текущее состояние.

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

Решение 2: Оптимизация через оконные функции (для 8.3.15+)

Если ваша платформа версии 8.3.15 или выше, мы можем использовать возможности современных СУБД через механизмы платформы. Хотя в языке запросов 1С оконные функции в явном виде ограничены, использование конструкций с АВТОНОМЕРЗАПИСИ() (в некоторых случаях) или просто грамотное использование физических таблиц вместо виртуальных может ускорить процесс.

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

Почему нельзя просто использовать Регистратор.Дата?

Выясним причину, по которой опытные разработчики предостерегают от обращения к дате регистратора через точку. Поле Регистратор в 1С является составным типом данных. Когда вы пишете Регистратор.Дата, SQL-запрос, генерируемый платформой, создает LEFT JOIN со всеми таблицами документов, которые могут быть регистраторами. Если их в системе 50 или 100 — производительность упадет катастрофически. Всегда используйте поле Период самого регистра — оно дублирует дату регистратора, уже проиндексировано и находится в той же таблице.

Практические советы по оптимизации

Рассмотрим несколько рекомендаций для стабильной работы системы:

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

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

← На главную