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

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

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

Разница между ПолучитьПоследнее и СрезПоследних

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

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

Рассмотрим на примере: если стул (основное средство) сначала числился в «Организации №1», а затем был перемещен в «Организацию №2», то в регистре будут две разные комбинации измерений. Запрос к срезу последних с отбором только по стулу вернет две строки: последнюю запись для «Организация №1» и последнюю для «Организация №2». Метод же ПолучитьПоследнее() ориентируется на поиск одной единственной записи, наиболее подходящей под переданный фильтр на указанный момент времени.

Разбор кода автора и типичные ошибки

Рассмотрим фрагмент кода, представленный в вопросе:


Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
               |    МестонахождениеОСБухгалтерскийУчетСрезПоследних.МОЛ КАК МОЛ,
               |    МестонахождениеОСБухгалтерскийУчетСрезПоследних.Местонахождение КАК Местонахождение,
               |    МестонахождениеОСБухгалтерскийУчетСрезПоследних.Период КАК Период,
               |    МестонахождениеОСБухгалтерскийУчетСрезПоследних.Регистратор КАК Регистратор
               |ИЗ
               |    РегистрСведений.МестонахождениеОСБухгалтерскийУчет.СрезПоследних(&Дата, ОсновноеСредство = &ОС) КАК МестонахождениеОСБухгалтерскийУчетСрезПоследних";
Запрос.УстановитьПараметр("Дата", Дата(2019, 7, 1));
Запрос.УстановитьПараметр("ОС", Справочники.ОсновныеСредства.НайтиПоНаименованию("Компьютер КМ Home522i RentiumDualCoreE2180"));

Здесь мы видим правильное использование параметров виртуальной таблицы. Автор передает &Дата и фильтр ОсновноеСредство = &ОС непосредственно в параметры таблицы СрезПоследних. Это критически важно для производительности. Если бы условие было вынесено в секцию ГДЕ, система сначала получила бы срез по всем записям всех ОС, а потом отфильтровала их, что привело бы к огромным затратам ресурсов сервера.

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

Как получить строго одну строку в запросе (Вариант 1: Срез по всем измерениям)

Если вам нужно получить данные по конкретному ОС в рамках конкретной организации, вы должны передать в параметры виртуальной таблицы отборы по всем измерениям регистра. Проанализируем, как это должно выглядеть:


// Предположим, в регистре измерения: ОсновноеСредство, Организация
Запрос.Текст = "ВЫБРАТЬ ... 
               |ИЗ РегистрСведений.МестонахождениеОСБухгалтерскийУчет.СрезПоследних(&Дата, 
               |    ОсновноеСредство = &ОС И Организация = &Организация) КАК Срез";

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

Как получить абсолютно последнюю запись (Вариант 2: Максимальный период)

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

  1. Найдем максимальную дату (момент времени) записи для данного объекта.
  2. Соединим полученную дату с основной таблицей регистра для получения ресурсов (МОЛ, Местонахождение).

Пример реализации такого запроса:


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

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

Важный нюанс: если в одну и ту же секунду (при периодичности «В пределах секунды») записано два документа по одному ОС, данный запрос может вернуть две строки. В этом случае для уточнения используют МоментВремени или Регистратор.

Архитектурный аспект: Измерения vs Ресурсы

Проанализируем ситуацию с точки зрения проектирования базы данных. В сообщениях форума справедливо отмечено: если вы хотите отслеживать перемещение объекта (например, мебели по комнатам), то «Местонахождение» должно быть ресурсом, а не измерением.

Запомните правило: Измерение — это разрез учета. То, что определяет уникальность записи. Если мы сделаем «Комнату» измерением, то для системы записи «Стул в комнате 1» и «Стул в комнате 2» — это два разных объекта наблюдения. Срез последних покажет актуальное состояние по каждой комнате отдельно.

Ресурс — это значение, которое меняется. Если «Комната» — ресурс, то срез последних по измерению «Стул» всегда покажет только одну (последнюю) комнату, где он находится.

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

Подводим итоги

Для правильного получения данных из регистра сведений придерживайтесь следующих рекомендаций:

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

Использование правильных методов работы с регистрами не только избавит от логических ошибок в отчетах, но и значительно ускорит работу вашей системы на больших объемах данных.

← На главную