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