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