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