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