Разработка и Конфигурация · 11 мин
Как получить срез последних на дату в запросе 1С
Как получить срез последних на дату в запросе 1С: параметры виртуальной таблицы, типовые запросы, соединения, ошибки и проверка результата.
Регистры сведений с режимом «Подчинение регистратору» отключенным и периодичностью хранят историю изменения значений: цены номенклатуры, курсы валют, ФИО сотрудников, ответственных лиц. Чтобы узнать, какое значение действовало на конкретную дату, не нужно перебирать записи вручную — платформа 1С предоставляет виртуальную таблицу «СрезПоследних», которая делает это за один запрос.
Главная сложность для начинающих разработчиков — правильно передать дату среза и понять, как виртуальная таблица соединяется с остальными данными. Неправильно построенный запрос либо возвращает пустой результат, либо, что хуже, не те значения: например, цену, которая будет установлена завтра, вместо действующей сегодня.
Материал разбирает синтаксис виртуальной таблицы «Срез последних», типовые сценарии с параметром даты и без него, соединение с документами и справочниками, а также типичные ошибки, которые приводят к неверным данным в отчётах.
Что такое виртуальная таблица «Срез последних»
Виртуальная таблица «СрезПоследних» доступна только у периодических регистров сведений. Для каждой комбинации измерений она возвращает одну запись — ту, у которой максимальный период не превышает заданную дату. Физически такой таблицы в базе нет: платформа строит её на лету при выполнении запроса.
Результат содержит все измерения регистра, все ресурсы и поле «Период» — дату той записи, которая была признана последней. Это важно: период в срезе — не дата, на которую строился срез, а дата фактической установки значения. По нему можно понять, насколько «свежие» данные получены.
Если регистр непериодический, виртуальных таблиц «СрезПоследних» и «СрезПервых» у него нет — обращение к ним вызовет ошибку компиляции запроса. Проверить периодичность можно в конфигураторе, в свойствах регистра сведений.
Базовый синтаксис запроса с датой среза
Минимальный запрос к срезу последних выглядит так:
ВЫБРАТЬ
Срез.Номенклатура,
Срез.Цена,
Срез.Период
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ) КАК Срез
Первый параметр виртуальной таблицы — период среза. Его принято передавать через параметр запроса, а не вшивать в текст:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ...";
Запрос.УстановитьПараметр("Период", КонецДня(ТребуемаяДата));
Обратите внимание на КонецДня(). Период сравнивается с точностью до секунды: если записи установлены в течение дня, а передать начало дня, записи, сделанные позже в этот же день, в срез не попадут. Для среза «на дату включительно» почти всегда нужен конец дня. Исключение — когда требуется состояние строго на начало дня, например для расчёта остатков по курсу на утро.
Запрос.УстановитьПараметр("Период", КонецДня(ДатаСреза));Второй параметр: отбор по измерениям
Второй параметр виртуальной таблицы — строка условия, аналогичная секции ГДЕ, но работающая только с полями самого регистра. Он позволяет ограничить срез до того, как платформа начнёт искать последние записи, что заметно ускоряет запрос на больших регистрах.
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
&Период,
ТипЦен = &ТипЦен И Номенклатура В (&СписокНоменклатуры)) КАК Срез
Практическое правило: всё, что можно отфильтровать по измерениям, фильтруйте именно здесь, а не в секции ГДЕ основного запроса. Условие внутри виртуальной таблицы уменьшает объём обрабатываемых записей, условие снаружи — уже построенный срез.
Если отбор не нужен, параметр оставляют пустым, но запятую после первого параметра сохраняют: СрезПоследних(&Период, ). Полностью опустить параметры тоже можно — тогда срез строится на текущую дату сеанса.
Соединение среза с документами и справочниками
На практике срез последних редко нужен сам по себе — обычно его присоединяют к табличной части документа или списку справочника. Классическая задача: подобрать цену для каждой строки реализации на дату документа.
ВЫБРАТЬ
Товары.Номенклатура,
Товары.Количество,
ЕСТЬNULL(Цены.Цена, 0) КАК Цена
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Товары
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ) КАК Цены
ПО Товары.Номенклатура = Цены.Номенклатура
Используется именно левое соединение: если для какой-то позиции цена не установлена, строка документа не должна пропадать. Функция ЕСТЬNULL подставляет ноль вместо NULL, чтобы дальше значение участвовало в расчётах.
Соединение всегда выполняется по полному набору измерений, участвующих в логике. Если у регистра два измерения (например, «Номенклатура» и «ТипЦен»), а в условии соединения указано только одно — одна строка документа размножится на несколько строк результата. Лучше отфильтровать лишнее измерение во втором параметре виртуальной таблицы.
- 1Определите периодичность и измерения регистра сведений в конфигураторе
- 2Сформулируйте запрос к СрезПоследних с параметром &Период
- 3Добавьте отбор по измерениям во второй параметр виртуальной таблицы
- 4Соедините срез с основной таблицей по всем значимым измерениям через ЛЕВОЕ СОЕДИНЕНИЕ
- 5Установите параметр Период как КонецДня(ДатаСреза) и выполните запрос
- 6Проверьте результат на записи с известной историей изменений
Срез без даты и срез на каждую дату документа
Если параметр периода не задан (СрезПоследних()), платформа строит срез на текущую дату сеанса. Это удобно для подстановки актуальных значений в формы, но опасно в отчётах за прошлые периоды: отчёт «за вчера» покажет сегодняшние цены.
Отдельная задача — получить срез на дату каждого документа, когда документов много и даты разные. Простое соединение не подходит: параметр среза один на весь запрос. Типовое решение — сначала собрать пары «документ + измерение» с датами, затем соединить их с таблицей регистра по условию «Период <= ДатаДокумента» и сгруппировать с максимумом периода, после чего присоединить значения ресурсов.
Такая конструкция из двух соединений заметно тяжелее одиночного среза. На больших объёмах её выносят во временную таблицу с индексированием по измерениям либо ограничивают список обрабатываемых документов отбором.
Варианты получения значений на дату
Одна дата на весь запрос. Самый быстрый и простой вариант, подходит для отчётов на фиксированную дату.
Текущая дата сеанса. Удобно для форм и подстановки актуальных данных, не подходит для прошлых периодов.
Своя дата у каждой строки документа. Гибко, но тяжелее по производительности и сложнее в отладке.
Типичные ошибки и как их проверить
Самая частая ошибка — передача начала дня вместо конца. Симптом: значения, установленные сегодня, не попадают в срез «на сегодня». Лечится обёрткой КонецДня() или добавлением секунд к дате.
Вторая ошибка — внутреннее соединение вместо левого. Записи без установленного значения молча исчезают из результата, и отчёт занижает итоги. Третья — неполное условие соединения по измерениям, приводящее к задвоению строк и завышению сумм.
Ещё одна ловушка — регистр с режимом записи «Подчинение регистратору». У таких регистров срез учитывает и регистратора при равенстве периодов: платформа выбирает запись с максимальным периодом, а при равных периодах — с бо́льшим регистратором по порядку сравнения ссылок. Если два документа установили значение одной секундой, результат может отличаться от ожидаемого.
Как проверить результат среза
Период не позже даты среза, значение соответствует последней записи в форме списка регистра
Период позже даты среза или значение не совпадает с историей записей
Совпадает с количеством строк исходной таблицы
Строк стало больше — дубли из-за неполного условия соединения
Присутствуют в результате с NULL или 0 в ресурсах
Отсутствуют — использовано внутреннее соединение
Производительность и ограничения
Срез последних — ресурсоёмкая операция: платформа ищет максимальный период по каждой комбинации измерений. На регистрах с сотнями тысяч записей запрос без отбора может выполняться секунды и десятки секунд. Основные приёмы ускорения: отбор во втором параметре виртуальной таблицы, ограничение состава выбираемых полей и использование временных таблиц при повторном обращении к тому же срезу в пакетном запросе.
Индексы по измерениям регистра платформа создаёт автоматически, поэтому дополнительной настройки обычно не требуется. Если запрос всё равно медленный, проверьте план запроса в консоли или через технологический журнал — часто причина в соединении среза с непроиндексированной временной таблицей.
Помните и о логическом ограничении: срез последних не «отменяет» записи будущим периодом при построении на прошлую дату — он их просто не видит. Но если данные за прошлый период были перепроведены или изменены задним числом, срез на ту же дату даст уже другой результат. Для отчётов, где важна воспроизводимость, сохраняйте результаты или фиксируйте версии данных.
FAQ по срезу последних
Чем срез последних отличается от среза первых?
СрезПервых возвращает самую раннюю запись на дату или после неё — например, первое установленное значение цены. СрезПоследних — самую позднюю не позже даты, то есть актуальное на этот момент значение. Для подстановки действующих цен, курсов и ответственных используется именно срез последних.
Как получить срез последних по конкретному элементу справочника?
Передайте условие во втором параметре виртуальной таблицы: СрезПоследних(&Период, Номенклатура = &Номенклатура). Ссылку на элемент установите параметром запроса через УстановитьПараметр. Так платформа построит срез только по нужной позиции, а не по всему регистру.
Почему срез на сегодня не видит записи, введённые сегодня?
Почти всегда причина в том, что параметром передано начало дня, а запись сделана позже в течение дня. Период сравнивается с точностью до секунды. Передайте КонецДня(ДатаСреза), и записи текущего дня попадут в срез.
Можно ли использовать срез последних в СКД?
Да, виртуальная таблица доступна в запросе набора данных компоновки. Период удобно связать с параметрами СКД через выражение &Период в тексте запроса, а сам параметр добавить на закладке «Компоновка данных», чтобы пользователь выбирал дату среза в настройках отчёта.
Что вернёт срез, если по измерению нет ни одной записи?
Для такой комбинации измерений строка в виртуальной таблице просто не появится — это не NULL-запись, а отсутствие записи. Поэтому при соединении со списком объектов используйте левое соединение и обрабатывайте NULL через ЕСТЬNULL.
Как получить срез на дату каждого документа, а не на одну общую?
Параметр виртуальной таблицы один на весь запрос, поэтому нужен обходной путь: соберите таблицу «документ — измерение — дата», соедините её с физической таблицей регистра по условию Период <= ДатаДокумента, сгруппируйте с МАКСИМУМ(Период), затем по найденному периоду присоедините значения ресурсов вторым соединением.
Что важно запомнить
Срез последних на дату строится виртуальной таблицей СрезПоследних(&Период, Отбор). Дату передавайте как КонецДня, отборы размещайте внутри параметров виртуальной таблицы, соединяйтесь по всем измерениям левым соединением и проверяйте результат по полю Период и количеству строк.