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

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

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

Выясним причину сложности и архитектуру решения

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

Рассмотри основные способы решения этой задачи с помощью языка запросов 1С.

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

Разберем по шагам наиболее эффективный и прозрачный подход — использование пакета запросов с временной таблицей. Данный вариант легко читается и демонстрирует отличную производительность.

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

Посмотрим на пример BSL-кода запроса:


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

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

Способ 2. Вложенный запрос и проверка по составному ключу

Альтернативный вариант позволяет обойтись без создания явно поименованной временной таблицы с помощью конструкции В в секции ГДЕ. Этот способ удобен, когда запрос необходимо встроить в качестве одного из подзапросов в крупную выборку.

Проанализируем пример конструкции с составным отбором:


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

Оптимизированный запрос для получения состояния по одному конкретному сотруднику

Если задача заключается не в получении среза по всей базе, а в сведении данных только для одного известного объекта, использовать группировки и соединения не требуется. Достаточно отсортировать данные по убыванию даты и взять первую запись.

Рассмотрим пример такого запроса:


ВЫБРАТЬ ПЕРВЫЕ 1
    Регистр.Состояние КАК Состояние
ИЗ
    РегистрСведений.СостоянияСотрудников КАК Регистр
ГДЕ
    Регистр.Сотрудник = &Сотрудник
    И Регистр.ПериодРаботы <= &Дата
УПОРЯДОЧИТЬ ПО
    Регистр.ПериодРаботы УБЫВ

Важные риски и производительность

При использовании описанных подходов необходимо учитывать несколько технических нюансов:

  1. Риск задвоения строк при одинаковых датах: Если в регистр попадут две разные записи по одному и тому же сотруднику с абсолютно одинаковой максимальной датой, то внутреннее соединение вернет обе записи. Чтобы избежать дубликатов, в реальных системах дополнительно связывают записи по второстепенным полям (например, НомерСтроки) или добавляют итоговую группировку.
  2. Индексация: В непериодическом регистре сведений платформа 1С не создает автоматически индексы под таблицы срезов. Чтобы запрос выполнялся максимально быстро, убедитесь, что измерение Сотрудник в структуре метаданных находится выше поля ПериодРаботы, либо у поля даты явно установлено свойство Индексировать.
  3. Архитектурная рекомендация: Если структура конфигурации позволяет внести изменения в метаданные, наиболее правильным решением будет перевести регистр сведений в статус Периодический. Это позволит штатно задействовать виртуальную таблицу РегистрСведений.СостоянияСотрудников.СрезПоследних(&Дата), которая оптимизирована на уровне платформы 1С и СУБД.
← На главную