К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как сделать срез последних в запросе 1С

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

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

Механизм среза последних доступен только для периодических регистров сведений. Для непериодических регистров понятие «последней записи» не определено, поэтому попытка обратиться к виртуальной таблице СрезПоследних у такого объекта приведёт к ошибке компиляции запроса. Перед написанием запроса убедитесь, что в свойствах регистра установлена периодичность: в пределах секунды, дня, месяца, квартала или года, либо выбран режим «По позиции документа».

Типовая задача выглядит так: нужно получить цены товаров на текущую дату, действующий курс валюты или ФИО сотрудника с учётом последнего изменения. Во всех этих случаях запрос строится по одному шаблону — обращение к виртуальной таблице с указанием момента времени и, при необходимости, условия отбора по измерениям.

Что такое срез последних и когда он нужен

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

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

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

Синтаксис виртуальной таблицы СрезПоследних

Обращение к виртуальной таблице записывается в секции ИЗ (FROM) запроса. Полное имя формируется по шаблону: РегистрСведений.ИмяРегистра.СрезПоследних. В скобках указываются два параметра: период среза и условие отбора. Оба параметра не обязательны, но на практике период задают почти всегда — иначе срез выполняется на максимально возможную дату, что редко соответствует бизнес-задаче и замедляет выборку.

ВЫБРАТЬ

Цены.Номенклатура КАК Номенклатура,

Цены.Цена КАК Цена

ИЗ

РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ) КАК Цены

Первый параметр — момент времени, на который строится срез. В него можно передать дату, переменную типа МоментВремени или границу. Если передать пустую дату, платформа вернёт записи без ограничения по периоду. Второй параметр — строка условия на языке запросов, которая накладывается на измерения регистра до построения среза.

Если параметры не нужны, скобки можно опустить, но в консоли запросов и при программной передаче параметров лучше всегда указывать их явно — это делает код предсказуемым и упрощает отладку.

Передача параметров и условие отбора по измерениям

Параметр периода передаётся в запрос стандартно — через метод УстановитьПараметр объекта Запрос. Дата включается в срез: запись, у которой период в точности равен переданной дате, попадёт в результат. Если нужен срез «строго раньше» даты, используют объект Граница с видом «Исключая».

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Курсы.Валюта КАК Валюта,

| Курсы.Курс КАК Курс

|ИЗ

| РегистрСведений.КурсыВалют.СрезПоследних(&Период, Валюта = &Валюта) КАК Курсы";

Запрос.УстановитьПараметр("Период", ТекущаяДатаСеанса());

Запрос.УстановитьПараметр("Валюта", ВалютаUSD);

Во втором параметре допустимы составные условия через И и ИЛИ, сравнения, проверка В ИЕРАРХИИ и В (&Список). Чем уже отбор по измерениям, тем меньше записей обрабатывает платформа при построении виртуальной таблицы, поэтому отбор всегда выгоднее помещать в параметры виртуальной таблицы, а не в секцию ГДЕ.

Порядок действий
  1. 1
    Убедитесь, что регистр сведений периодический (свойство «Периодичность» не равно «Непериодический»)
  2. 2
    Напишите запрос с обращением к РегистрСведений.Имя.СрезПоследних(&Период, Условие)
  3. 3
    Передайте параметр периода через УстановитьПараметр
  4. 4
    При необходимости добавьте отбор по измерениям вторым параметром
  5. 5
    Проверьте результат в консоли запросов на тестовых данных с несколькими записями истории

Соединение среза с другими таблицами

На практике срез последних редко используют отдельно — обычно его соединяют с таблицей документа или справочника. Типовой пример: к списку номенклатуры из табличной части документа присоединить актуальные цены. Соединение выполняется по всем измерениям регистра, участвующим в задаче.

ВЫБРАТЬ

Товары.Номенклатура КАК Номенклатура,

Товары.Количество КАК Количество,

ЕСТЬNULL(Цены.Цена, 0) КАК Цена

ИЗ

Документ.РеализацияТоваровУслуг.Товары КАК Товары

ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ) КАК Цены

ПО Товары.Номенклатура = Цены.Номенклатура

ГДЕ

Товары.Ссылка = &Ссылка

Левое соединение выбирают сознательно: если для части позиций цена в регистре не задана, строки не должны пропадать из результата. Функция ЕСТЬNULL заменяет NULL на ноль или другое значение по умолчанию, чтобы в отчёте не было пустых ячеек и ошибок расчёта суммы.

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

Если срез соединяется с табличной частью документа, передавайте в параметр периода дату самого документа, а не текущую дату. Иначе при перепроведении старых документов или построении отчёта за прошлый период цены и курсы будут взяты «на сегодня», что исказит данные.
ПЗ
Практическое замечание

Ручной срез последних через МАКСИМУМ

В некоторых ситуациях виртуальная таблица не подходит: нужна дата из другой таблицы для каждой строки, требуется срез по нестандартному условию или запрос выполняется в СКД со сложной логикой. Тогда срез строят вручную — группировкой по измерениям с агрегатной функцией МАКСИМУМ по периоду, а затем соединением с основной таблицей регистра для получения ресурсов.

ВЫБРАТЬ

Курсы.Валюта КАК Валюта,

МАКСИМУМ(Курсы.Период) КАК Период

ПОМЕСТИТЬ ПоследниеПериоды

ИЗ

РегистрСведений.КурсыВалют КАК Курсы

ГДЕ

Курсы.Период <= &Период

СГРУППИРОВАТЬ ПО

Курсы.Валюта

;

ВЫБРАТЬ

ПоследниеПериоды.Валюта КАК Валюта,

Курсы.Курс КАК Курс

ИЗ

ПоследниеПериоды КАК ПоследниеПериоды

ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК Курсы

ПО ПоследниеПериоды.Валюта = Курсы.Валюта

И ПоследниеПериоды.Период = Курсы.Период

У ручного способа есть тонкость: если на одну дату по одному набору измерений существует несколько записей (что возможно при периодичности «в пределах секунды» или «по позиции документа»), соединение вернёт дубли. Виртуальная таблица разрешает такие коллизии за счёт регистратора, а в ручном варианте это придётся обрабатывать самостоятельно — например, добавив в группировку максимум регистратора.

Сравнение вариантов

Виртуальная таблица СрезПоследних

Подходит для одной фиксированной даты среза. Проще писать, платформа сама разрешает коллизии. Не работает с разными датами по строкам.

Ручной срез через МАКСИМУМ

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

Производительность и типичные ошибки

Главный фактор скорости — отбор по измерениям в параметрах виртуальной таблицы. Срез по всей номенклатуре за десять лет истории может занимать секунды, тогда как тот же срез с условием «Номенклатура В (&Список)» выполнится быстро. Второй фактор — индексы: измерения регистра индексируются платформой, поэтому условия именно по измерениям работают эффективно.

Частая ошибка — соединение виртуальной таблицы без ограничения её состава внутри большого пакетного запроса. Оптимизатор СУБД в таких случаях может построить срез по всем записям регистра, даже если соединение затем отфильтрует лишнее. Правило простое: всё, что можно отфильтровать на входе, фильтруйте параметром виртуальной таблицы.

Типичные ошибки
01
Обращение к СрезПоследних у непериодического регистра — ошибка компиляции запроса
02
Отбор по измерениям в секции ГДЕ вместо параметра виртуальной таблицы — лишнее сканирование и медленный запрос
03
Внутреннее соединение вместо левого — строки без записей в регистре пропадают из результата
04
Передача текущей даты вместо даты документа — некорректные значения при работе с прошлыми периодами
05
Фильтрация по ресурсам в параметре виртуальной таблицы — синтаксическая ошибка, ресурсы там недоступны

Проверка результата и отладка

После написания запроса проверьте его в консоли запросов на контрольном примере: возьмите объект с несколькими записями истории и убедитесь, что возвращается именно последняя на заданную дату. Полезно сравнить результат со стандартным отчётом «Список/кросс-таблица» по регистру или с ручным просмотром записей в режиме предприятия.

Контрольные точки

Как проверить результат

Количество строк в срезе
Норма

По одной строке на каждую комбинацию измерений

Тревожный признак

Дубли строк — вероятно, несколько записей на один период, нужен учёт регистратора

Значение ресурса
Норма

Совпадает с последней записью на дату среза в режиме предприятия

Тревожный признак

Возвращается не последнее значение — проверьте параметр периода и часовой пояс сеанса

Строки без данных в регистре
Норма

При левом соединении присутствуют с NULL, обработанным через ЕСТЬNULL

Тревожный признак

Строки пропали — использовано внутреннее соединение

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

Итог

Что важно запомнить

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

Частые вопросы

Можно ли сделать срез последних без указания периода?

Да, параметр периода можно опустить: РегистрСведений.Цены.СрезПоследних(, Условие). Тогда платформа вернёт самые последние записи по всей истории без ограничения даты. Такой вариант допустим, когда нужны актуальные значения «на сейчас», но он обрабатывает весь регистр и обычно медленнее среза на конкретную дату.

Почему срез последних возвращает дубли строк?

Дубли появляются, когда на один и тот же период по одному набору измерений записано несколько строк — например, при периодичности «по позиции документа» или «в пределах секунды». Виртуальная таблица обычно учитывает регистратор и возвращает одну запись, но при ручном срезе через МАКСИМУМ коллизию нужно разрешать самостоятельно, добавляя в группировку максимум регистратора.

Как получить срез последних на дату каждого документа в выборке?

Одна виртуальная таблица с фиксированным параметром здесь не подойдёт. Используйте ручной срез: сгруппируйте регистр по измерениям и документам с условием Период <= ДатаДокумента, найдите МАКСИМУМ(Период) для каждой пары и соедините результат с регистром для получения ресурсов. Либо разбейте выборку на группы по датам и выполните несколько запросов с разными параметрами.

Чем срез первых отличается от среза последних?

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

Работает ли срез последних в СКД и динамических списках?

Да, в схеме компоновки данных виртуальная таблица используется так же, как в обычном запросе, а параметр периода удобно связывать с параметром отчёта. В динамических списках срез последних применять не рекомендуется: динамический список перечитывает данные при прокрутке, и тяжёлая виртуальная таблица будет заметно тормозить работу формы.

Как учесть часовые пояса при передаче даты среза?

Платформа хранит периоды в абсолютном времени, а функция ТекущаяДатаСеанса возвращает дату в часовом поясе сеанса. Если пользователи работают в разных поясах, передавайте в параметр осознанно выбранное значение: дату документа, универсальное время или дату сеанса — в зависимости от бизнес-логики. Несогласованность здесь даёт ситуацию, когда запись «ещё не наступила» для одного пользователя и уже видна другому.