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

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

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

Как получить максимальное значение в запросе 1С: агрегатная функция МАКСИМУМ, группировки, максимум без группировки, работа с NULL, типичные ошибки и примеры кода.

Задача получить максимальное значение в запросе 1С встречается постоянно: найти последнюю цену товара, максимальную дату документа, наибольший номер накладной, самую высокую сумму продажи. В языке запросов 1С для этого предусмотрена агрегатная функция МАКСИМУМ (английский синоним — MAX), однако у неё есть нюансы: поведение с NULL, необходимость группировки, ограничения на типы данных.

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

Ниже разобраны все рабочие варианты с готовыми текстами запросов, условиями применения, способами проверки результата и типичными ошибками, из-за которых запрос возвращает не то, что ожидалось.

Агрегатная функция МАКСИМУМ: базовый синтаксис

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

ВЫБРАТЬ

МАКСИМУМ(ПоступлениеТоваров.Дата) КАК МаксимальнаяДата

ИЗ

Документ.ПоступлениеТоваровУслуг КАК ПоступлениеТоваров

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

Аргументом функции может быть не только поле таблицы, но и выражение: МАКСИМУМ(Таб.Количество * Таб.Цена). Ограничение — функция не работает с полями неограниченной длины (строки без указания размера) и полями типа ХранилищеЗначения: сравнение таких значений в запросе невозможно.

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

Максимум в разрезе групп: СГРУППИРОВАТЬ ПО

Чаще всего нужен не общий максимум, а максимальный показатель по каждому объекту: последняя дата продажи по каждому товару, максимальная цена по каждому поставщику. Для этого поля-измерения выносятся в секцию группировки:

ВЫБРАТЬ

Продажи.Номенклатура КАК Номенклатура,

МАКСИМУМ(Продажи.Период) КАК ПоследняяПродажа

ИЗ

РегистрНакопления.Продажи КАК Продажи

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

Продажи.Номенклатура

Ключевое правило: любое поле в списке выборки, не обёрнутое в агрегатную функцию, обязано присутствовать в СГРУППИРОВАТЬ ПО. Нарушение — самая частая причина ошибки «Неверные поля группировки» при сохранении запроса в консоли или в модуле.

Дополнительно можно отфильтровать группы по значению максимума через ИМЕЮЩИЕ. Например, оставить только товары, по которым последняя продажа была раньше заданной даты — типичный запрос для поиска «залежавшихся» позиций:

ИМЕЮЩИЕ

МАКСИМУМ(Продажи.Период) < &ГраницаДаты

Как построить запрос с группировкой
  1. 1
    Определите измерение, в разрезе которого нужен максимум (товар, контрагент, склад)
  2. 2
    Добавьте это поле в список выборки и в СГРУППИРОВАТЬ ПО
  3. 3
    Добавьте МАКСИМУМ(ПолеПоказателя) с понятным псевдонимом
  4. 4
    При необходимости задайте условие ИМЕЮЩИЕ для отбора групп
  5. 5
    Проверьте результат в консоли запросов на копии базы

Максимум без группировки и работа с NULL

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

Вторая ловушка: если выборка пуста или все значения равны NULL, функция вернёт NULL. В коде это обрабатывают через ЕСТЬNULL прямо в запросе или проверкой в модуле:

ВЫБРАТЬ

ЕСТЬNULL(МАКСИМУМ(Таб.Номер), 0) КАК МаксимальныйНомер

ИЗ

Документ.СчетНаОплату КАК Таб

Приём с ЕСТЬNULL(..., 0) удобен при генерации следующего номера строки или документа вручную: к полученному максимуму прибавляют единицу. Учтите, что такой способ нумерации небезопасен при параллельной работе пользователей — два сеанса могут получить одинаковый максимум. Для штатной нумерации используйте встроенный механизм номеров документов.

Если максимум вычисляется по виртуальной таблице с параметрами (например, Остатки регистра накопления), убедитесь, что отборы виртуальной таблицы заданы корректно: пустой результат виртуальной таблицы также приведёт к NULL.

Вся строка с максимальным значением: ПЕРВЫЕ 1 и УПОРЯДОЧИТЬ ПО

Агрегатная функция возвращает только само значение. На практике чаще нужна вся запись: документ с максимальной датой, строка с последней ценой. Здесь помогает сортировка по убыванию с ограничением выборки:

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

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

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

Цены.Период КАК Период

ИЗ

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

ГДЕ

Цены.Номенклатура = &Номенклатура

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

Цены.Период УБЫВ

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

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

Три способа получить максимум

МАКСИМУМ с группировкой

Подходит, когда нужно только значение максимума по одному или нескольким измерениям. Не возвращает остальные поля строки.

ПЕРВЫЕ 1 + УПОРЯДОЧИТЬ ПО УБЫВ

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

Виртуальная таблица СрезПоследних

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

Соединение с подзапросом максимума

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

ВЫБРАТЬ

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

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

Цены.Регистратор КАК Регистратор

ИЗ

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

ВНУТРЕННЕЕ СОЕДИНЕНИЕ (

ВЫБРАТЬ

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

МАКСИМУМ(Т.Период) КАК МаксПериод

ИЗ

РегистрСведений.ЦеныНоменклатуры КАК Т

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

Т.Номенклатура) КАК Максимумы

ПО Цены.Номенклатура = Максимумы.Номенклатура

И Цены.Период = Максимумы.МаксПериод

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

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

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

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

Любой запрос с максимумом стоит проверить в консоли запросов на копии рабочей базы до переноса в код. Контрольные точки: количество строк результата соответствует ожиданию (одна для общего максимума, по числу групп — для группировки), значения не равны NULL там, где данные есть, даты попадают в ожидаемый диапазон.

Дополнительная проверка — сравнение с эталоном: выполните тот же запрос сортировкой по убыванию и посмотрите первую строку. Значение в ней должно совпасть с результатом МАКСИМУМ. Расхождение означает, что в запросе есть скрытый отбор или соединение, отсекающее часть данных.

В коде модуля результат читают через выборку: даже когда строка гарантированно одна, результат запроса — таблица, поэтому используют Выборка.Следующий() и затем обращение к полю. Не забудьте проверить Результат.Пустой и значение на NULL перед использованием.

Типичные ошибки
01
Поле в списке выборки не входит в СГРУППИРОВАТЬ ПО и не обёрнуто агрегатной функцией — ошибка группировки при выполнении
02
Ожидание нуля вместо NULL: МАКСИМУМ по пустой выборке возвращает NULL, арифметика с NULL даёт NULL
03
ПЕРВЫЕ 1 без УПОРЯДОЧИТЬ ПО — возвращается произвольная строка, а не максимальная
04
Максимум по незаполненному полю даты: пустая дата 01.01.0001 участвует в сравнении и искажает результат
05
Попытка применить МАКСИМУМ к строке неограниченной длины — запрос не выполняется
Контрольные точки

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

Число строк результата
Норма

Одна строка для общего максимума, по числу групп — для СГРУППИРОВАТЬ ПО

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

Строк больше, чем групп, — вероятны дубли в соединении

Значение максимума
Норма

Совпадает с первой строкой при сортировке по убыванию того же поля

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

Значение NULL при наличии данных — проверьте отборы и соединения

Поведение в коде
Норма

ЕСТЬNULL задаёт значение по умолчанию, дальнейшие вычисления корректны

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

Сравнение или сложение с NULL даёт пустой результат без явной ошибки

Производительность и ограничения

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

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

Избегайте вычисления максимума в цикле по строкам таблицы значений или списка ссылок — это классическая ошибка «запрос в цикле». Правильный подход: один запрос с группировкой по всем нужным измерениям сразу, затем обход готового результата.

Итог

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

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

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

Чем МАКСИМУМ отличается от ПЕРВЫЕ 1 с сортировкой?

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

Почему МАКСИМУМ вернул NULL, хотя данные в таблице есть?

Три вероятные причины: отбор в секции ГДЕ отсекает все записи, соединение с другой таблицей не находит соответствий, либо само поле во всех отобранных строках равно NULL. Проверьте запрос без условий, а затем добавляйте отборы по одному, чтобы найти отсекающий.

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

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

Как получить максимальное значение в СКД?

В схеме компоновки данных агрегирование выполняется на уровне ресурсов: добавьте поле в ресурсы и выберите выражение Максимум(Поле). В тексте самого запроса набора данных при этом можно оставить детальные записи без группировки — СКД свернёт их при формировании отчёта.

Работает ли МАКСИМУМ со строковыми полями?

Да, для строк ограниченной длины функция возвращает наибольшее значение по правилам сортировки строк (с учётом регистра и алфавитного порядка). Строки неограниченной длины и поля типа ХранилищеЗначения агрегировать нельзя — запрос завершится ошибкой.

Как получить максимальную дату документа с учётом времени?

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