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