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

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

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

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

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

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

Важный нюанс: дата документа в 1С не всегда уникальна. Несколько документов могут иметь одинаковую дату с точностью до секунды, а при отключённом режиме «Дата и время» — даже одинаковую дату без времени. Поэтому простой отбор по максимальной дате может вернуть несколько строк, и это нужно учитывать в логике запроса.

Способ 1: ПЕРВЫЕ 1 с упорядочиванием по убыванию даты

Самый короткий и читаемый вариант — отсортировать документы по дате по убыванию и взять первую строку. Конструкция ПЕРВЫЕ 1 указывается сразу после ВЫБРАТЬ, а упорядочивание — в конце запроса.

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

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

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

ИЗ

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

ГДЕ

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

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

Дата УБЫВ

Обязательно добавляйте отбор Проведен, если вас интересуют только проведённые документы — иначе запрос может вернуть помеченный на удаление или непроведённый документ, созданный позже всех. Если нужен последний документ по конкретному контрагенту, добавьте условие на реквизит: ГДЕ РеализацияТоваровУслуг.Контрагент = &Контрагент.

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

Способ 2: МАКСИМУМ с группировкой и соединением

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

ВЫБРАТЬ

Реализация.Контрагент КАК Контрагент,

МАКСИМУМ(Реализация.Дата) КАК МаксДата

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

ИЗ

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

ГДЕ

Реализация.Проведен

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

Реализация.Контрагент

;

ВЫБРАТЬ

Реализация.Контрагент КАК Контрагент,

Реализация.Ссылка КАК ПоследнийДокумент

ИЗ

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

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

ПО Реализация.Контрагент = МаксДаты.Контрагент

И Реализация.Дата = МаксДаты.МаксДата

ГДЕ

Реализация.Проведен

Главный недостаток этого подхода — возможные дубли. Если у контрагента два проведённых документа с одинаковой датой, соединение вернёт оба. Бороться с этим можно двумя путями: либо свернуть результат группировкой с МАКСИМУМ(Реализация.Ссылка), либо усложнить соединение, выбрав максимальную ссылку среди документов с максимальной датой.

На больших таблицах такой запрос выполняет два чтения таблицы документов. Если документов миллионы, запрос может работать заметно дольше, чем вариант с ПЕРВЫЕ 1. В этом случае ограничивайте выборку периодом (Дата МЕЖДУ &Начало И &Конец) или списком контрагентов через параметр-таблицу значений.

Типичные ошибки
01
Соединение по дате без учёта дублей — в результате появляются лишние строки и задваиваются суммы в отчётах
02
Отсутствие отбора Проведен — последним оказывается помеченный на удаление документ
03
Сравнение дат без времени — документы за один день считаются одинаковыми, и выбирается произвольный
04
Использование МАКСИМУМ(Ссылка) без даты — ссылка не гарантирует хронологию при изменении дат документов вручную

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

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

ВЫБРАТЬ

СрезПоследних.Номенклатура КАК Номенклатура,

СрезПоследних.Цена КАК Цена,

СрезПоследних.Регистратор КАК ДокументУстановки

ИЗ

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

Поле Регистратор в срезе последних — это и есть документ, которым была установлена последняя цена или значение. Так вы получаете и значение, и документ-источник одним запросом, без ручного поиска максимальной даты.

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

Сравнение способов и выбор подхода

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

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

Как выбрать действие

Нужен один последний документ по условиюИспользуйте ПЕРВЫЕ 1 с УПОРЯДОЧИТЬ ПО Дата УБЫВ, Ссылка УБЫВ
Нужны последние документы по каждому объекту из спискаСтройте временную таблицу с МАКСИМУМ(Дата) и соединяйте с таблицей документов
Данные хранятся в периодическом регистре сведенийИспользуйте СрезПоследних и берите документ из поля Регистратор
Таблица документов очень большаяОграничьте выборку периодом и списком объектов до вычисления максимума

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

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

Обратите внимание на граничные случаи: объект без единого проведённого документа (в разрезе по такому объекту не будет строки — это норма для ВНУТРЕННЕГО соединения, но при ЛЕВОМ соединении появится NULL), документы с одинаковой датой, документы, проведённые задним числом после того, как запрос уже использовался в расчётах.

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

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

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

Дата найденного документа
Норма

Совпадает с максимальной датой проведённых документов в журнале

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

В журнале есть более поздний проведённый документ — проверьте отборы

Количество строк по объекту
Норма

Одна строка на каждый объект разреза

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

Несколько строк с одинаковой датой — добавьте выбор максимальной ссылки

Период среза
Норма

Передан явно через параметр

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

Параметр пуст — результат зависит от текущей даты сеанса

Альтернативы: обход выборки и момент времени

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

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

Итог

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

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

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

Почему запрос с МАКСИМУМ(Дата) возвращает несколько документов?

Потому что у нескольких проведённых документов может быть одинаковая дата с точностью до секунды. Соединение по равенству даты возвращает все такие документы. Решение — дополнительно выбрать максимальную ссылку среди них или использовать упорядочивание по моменту времени.

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

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

Чем СрезПоследних лучше ручного поиска максимальной даты?

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

Нужно ли сортировать по ссылке вдобавок к дате?

Да, если важна предсказуемость результата. При равных датах СУБД вернёт произвольную строку. Сортировка Дата УБЫВ, Ссылка УБЫВ или по полю МоментВремени гарантирует, что будет выбран документ, созданный позже.

Как получить последний документ, если проведённых документов у объекта нет?

При внутреннем соединении такой объект просто не попадёт в результат. Если нужно показать объект с пустым документом, используйте левое соединение списка объектов с таблицей максимальных дат и обрабатывайте значение NULL в поле документа.

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

Да. Добавьте условие Дата МЕЖДУ &Начало И &Конец в обе части запроса (и в группировку с МАКСИМУМ, и в соединяемую таблицу). Это не только даст корректный результат за период, но и заметно ускорит запрос на больших базах.