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

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

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

Как получить последний документ в запросе 1С: сортировка по дате и ссылке, ПЕРВЫЕ 1, МАКСИМУМ, типичные ошибки с моментом времени и примеры кода запросов.

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

Ключевая сложность в том, что «последний» в 1С определяется не только датой, но и моментом времени документа. Два документа, проведённые в одну секунду или с одинаковой датой, упорядочиваются по ссылке, и если сортировать только по дате, можно получить не тот документ, который реально является последним в последовательности.

Ниже разобраны рабочие способы: через ПЕРВЫЕ 1 с сортировкой по моменту времени, через МАКСИМУМ по дате с уточняющим соединением, а также вариант с виртуальной таблицей среза последних для регистров сведений. Для каждого способа приведены условия применения, примеры кода и типичные ошибки.

Что считается «последним» документом в 1С

Платформа 1С хранит у документа дату с точностью до секунды, но порядок внутри одной секунды и в целом в последовательности определяется моментом времени. Момент времени — это комбинация даты и ссылки на документ. Именно по нему платформа упорядочивает документы при проведении и восстановлении последовательностей.

Практическое следствие: сортировка УПОРЯДОЧИТЬ ПО Дата УБЫВ не гарантирует корректный результат. Если два документа созданы с одинаковой датой (например, загружены пакетно или перепроведены задним числом), запрос может вернуть любой из них, и результат будет отличаться от того, что видит пользователь в журнале документов.

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

Способ 1: ПЕРВЫЕ 1 с сортировкой по моменту времени

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

ВЫБРАТЬ ПЕРВЫЕ 1

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

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

РеализацияТоваровУслуг.Номер КАК Номер

ИЗ

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

ГДЕ

РеализацияТоваровУслуг.Контрагент = &Контрагент

И РеализацияТоваровУслуг.Проведен

УПОРЯДОЧИТЬ ПО

РеализацияТоваровУслуг.МоментВремени УБЫВ

Отбор по признаку Проведен важен: помеченные на удаление и непроведённые документы обычно не должны считаться «последними действующими», иначе запрос вернёт документ, который не участвует в учёте. Если нужен последний документ независимо от состояния, условие убирают, но это должно быть осознанным решением.

Можно сортировать и по полю Дата УБЫВ с добавлением Ссылка УБЫВ вторым ключом — по сути это вручную воспроизводит момент времени. Однако чтение поля МоментВремени напрямую короче и однозначнее.

Способ 2: последний документ по каждому объекту через МАКСИМУМ

Частая вариация задачи — получить последний документ не один, а для каждого контрагента, склада или номенклатуры. Здесь ПЕРВЫЕ 1 не подходит, потому что ограничивает всю выборку. Решение строится в два этапа: сначала агрегатный запрос находит максимальную дату по каждому объекту, затем результат соединяется с таблицей документов.

ВЫБРАТЬ

Док.Контрагент КАК Контрагент,

МАКСИМУМ(Док.Дата) КАК МаксДата

ПОМЕСТИТЬ МаксДаты

ИЗ

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

ГДЕ

Док.Проведен

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

Док.Контрагент

;

ВЫБРАТЬ

Док.Контрагент КАК Контрагент,

МАКСИМУМ(Док.Ссылка) КАК ПоследнийДокумент

ИЗ

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

ВНУТРЕННЕЕ СОЕДИНЕНИЕ МаксДаты КАК МаксДаты

ПО Док.Контрагент = МаксДаты.Контрагент

И Док.Дата = МаксДаты.МаксДата

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

Док.Контрагент

Обратите внимание на второй запрос: если у контрагента несколько документов с одинаковой максимальной датой, соединение даст несколько строк, поэтому применяется МАКСИМУМ(Ссылка) с группировкой. Максимальная ссылка при равной дате как раз соответствует более позднему моменту времени, поэтому результат корректен.

Альтернатива без временной таблицы — соединение таблицы документов с вложенным запросом, но вариант с ПОМЕСТИТЬ читается легче и обычно не хуже по производительности на типовых объёмах данных.

Способ 3: срез последних для регистров сведений

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

ВЫБРАТЬ

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

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

Цены.Регистратор КАК ПоследнийДокумент

ИЗ

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

Поле Регистратор в срезе последних и есть документ, которым была внесена актуальная запись. Этот способ быстрее ручного поиска максимума по документам, потому что платформа использует индексы регистра, и он корректно учитывает периодичность регистра.

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

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

ПЕРВЫЕ 1 + МоментВремени УБЫВ

Один последний документ по условию. Самый простой и надёжный вариант, но не подходит для группировки по объектам.

МАКСИМУМ(Дата) + соединение

Последний документ по каждому объекту (контрагенту, товару). Требует двух этапов и аккуратности при равных датах.

СрезПоследних регистра сведений

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

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

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

Ещё один способ контроля — временно убрать ПЕРВЫЕ 1 и посмотреть первые пять строк. Если на первой строке стоит не тот документ, который ожидался, проблема в упорядочивании или в отборе, а не в ограничении выборки.

Типичные ошибки
01
Сортировка только по Дата УБЫВ: при совпадающих датах возвращается произвольный документ, а не реально последний.
02
Отсутствие отбора по Проведен: запрос возвращает помеченный на удаление или черновой документ.
03
Использование МАКСИМУМ(Ссылка) без максимальной даты: ссылка не отражает хронологию, результат случаен.
04
Соединение по дате без МАКСИМУМ(Ссылка): при нескольких документах с одинаковой датой получаются дубли строк.
05
Поиск последнего документа по регистру вместо СрезПоследних: запрос работает медленнее и сложнее без необходимости.

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

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

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

Порядок сортировки
Норма

Используется МоментВремени УБЫВ или Дата УБЫВ + Ссылка УБЫВ

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

Только Дата УБЫВ — порядок при равных датах непредсказуем

Отбор по состоянию
Норма

Есть условие Проведен (или осознанно снято)

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

В выборку попадают помеченные на удаление документы

Единственность результата
Норма

Запрос возвращает ровно одну строку на объект

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

Дубли строк при одинаковых датах документов

Практический порядок действий

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

Порядок действий
  1. 1
    Определите критерий: один последний документ или последний по каждому объекту (контрагенту, товару).
  2. 2
    Если данные фактически лежат в периодическом регистре сведений — используйте СрезПоследних и поле Регистратор.
  3. 3
    Для одного документа напишите запрос с ПЕРВЫЕ 1 и сортировкой МоментВремени УБЫВ, добавьте отбор по Проведен.
  4. 4
    Для группировки по объектам сделайте временную таблицу с МАКСИМУМ(Дата), соедините с документами и возьмите МАКСИМУМ(Ссылка).
  5. 5
    Проверьте результат на данных с совпадающими датами и на большом объёме — убедитесь, что нет дублей и запрос отрабатывает быстро.

После отладки запроса в консоли запросов переносите его в код модуля. Если результат используется программно, проверяйте, что выборка не пустая: когда документов по условию нет, ПЕРВЫЕ 1 вернёт пустой результат, и обращение к полям без проверки Выборка.Следующий() приведёт к ошибке.

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

FAQ

Можно ли получить последний документ без запроса, через встроенный язык?

Да, но менее эффективно: можно выбрать документы методом Выбрать() менеджера документа с обходом в обратном порядке и остановиться на первом подходящем. Такой вариант перебирает данные на клиенте или сервере приложений и на больших таблицах заметно медленнее запроса с ПЕРВЫЕ 1. Запрос предпочтительнее почти всегда.

Почему запрос с Дата УБЫВ возвращает не тот документ, что в журнале?

Журнал документов упорядочивается по моменту времени, который включает ссылку, а ваш запрос сортирует только по дате. При совпадении дат порядок строк в запросе не определён. Замените сортировку на МоментВремени УБЫВ — и результат совпадёт с журналом.

Как получить последний документ на заданную дату, а не вообще?

Добавьте в условие ограничение Док.Дата <= &Период и оставьте сортировку по моменту времени по убыванию с ПЕРВЫЕ 1. Так вы получите последний документ, существовавший на указанный момент. Для точности до секунды передавайте в параметр полную дату со временем, а не только день.

Что вернёт запрос, если подходящих документов нет?

Запрос выполнится без ошибки, но выборка будет пустой. В коде это нужно обрабатывать явно: проверять результат через Если Выборка.Следующий() Тогда ... КонецЕсли; или Результат.Пустой(). Иначе обращение к реквизитам несуществующего документа вызовет ошибку исполнения.

Нужно ли индексировать что-то специально для таких запросов?

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

Итог

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

Последний документ в 1С определяется моментом времени, а не только датой. Для одного документа используйте ПЕРВЫЕ 1 с сортировкой МоментВремени УБЫВ и отбором по Проведен; для группировки по объектам — МАКСИМУМ(Дата) с соединением и МАКСИМУМ(Ссылка); для регистров сведений — СрезПоследних с полем Регистратор. Всегда проверяйте результат на данных с совпадающими датами.