Работа с данными в системе 1С часто требует выборки предельных значений из больших массивов информации. Это может быть последняя дата документа в регистре, максимальная цена товара или самый высокий рейтинг контрагента. В языке запросов платформы существует мощный механизм агрегации, который позволяет решать подобные задачи без необходимости выгружать все данные в память и перебирать их в цикле.

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

Синтаксис и базовое использование функции МАКСИМУМ

Функция МАКСИМУМ в языке запросов 1С относится к агрегатным функциям. Она принимает одно поле выборки в качестве аргумента и возвращает наибольшее значение этого поля среди всех строк результирующего набора.

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

ВЫБРАТЬ

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

ИЗ

Документ.ПоступлениеДенежныхСредств КАК Касса

В данном случае система просканирует таблицу документа и вернет единственное значение — самую позднюю дату. Обратите внимание на использование алиаса КАК МаксДата, который позволяет обращаться к результату в программном коде.

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

Работа с группировками и несколькими измерениями

Часто требуется найти максимальное значение не по всей базе, а в разрезе определенных категорий. Например, нам нужно узнать максимальную сумму продажи для каждого менеджера. В этом случае функция МАКСИМУМ используется совместно с оператором ПО (GROUP BY).

ВЫБРАТЬ

Продажи.Менеджер,

МАКСИМУМ(Продажи.Сумма) КАК МаксСумма

ИЗ

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

ГДЕ

Продажи.Период МЕЖДУ &НачПериода И &КонПериода

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

Продажи.Менеджер

Здесь запрос разбивает выборку на группы по каждому менеджеру и вычисляет максимум внутри каждой группы. Критически важно, чтобы все неагрегированные поля в SELECT были перечислены в блоке СГРУППИРОВАТЬ ПО. Иначе вы получите ошибку синтаксиса при выполнении запроса.

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

📊 Какой тип запроса вы используете чаще всего?
Простой SELECT
Запрос с ГРУППИРОВКОЙ ПО
Вложенные запросы
Запросы к виртуальным таблицам

Использование вложенных запросов для фильтрации

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

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

ВЫБРАТЬ

Вложенный.Номенклатура,

Вложенный.Цена,

Вложенный.Дата

ИЗ

(ВЫБРАТЬ

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

МАКСИМУМ(Цены.Цена) КАК МаксЦена

ИЗ

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

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

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

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

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

И МаксЦены.МаксЦена = Цены.Цена

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

💡

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

Сравнение производительности: МАКСИМУМ vs УПОРЯДОЧИТЬ ПО

Альтернативным способом получения максимального значения является сортировка по убыванию и выбор первой строки с помощью ключевого слова ПЕРВЫЕ 1. Многие разработчики интуитивно выбирают этот метод, считая его более читаемым. Однако разница в производительности может быть колоссальной.

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

Использование УПОРЯДОЧИТЬ ПО заставляет базу данных отсортировать все отфильтрованные записи, даже если нам нужна только одна. Функция МАКСИМУМ при наличии индекса может просто обратиться к последнему элементу индексного дерева, что происходит мгновенно.

💡

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

Обработка пустых выборок и значений NULL

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

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

⚠️ Внимание: Никогда не предполагайте, что запрос с МАКСИМУМ вернет 0, если данных нет. Всегда проверяйте результат на ЕСТЬ NULL перед использованием.

Для безопасной работы рекомендуется использовать функцию ЕСТЬNULL прямо в тексте запроса. Она позволяет подменить значение NULL на заданный вами дефолт (например, 0 или дату начала эпохи).

ВЫБРАТЬ

ЕСТЬNULL(МАКСИМУМ(Движения.Количество), 0) КАК МаксКоличество

ИЗ

РегистрНакопления.ТоварыНаСкладах КАК Движения

Такой подход избавляет от необходимости писать лишние проверки в программном коде на встроенном языке 1С и делает запрос самодостаточным.

☑️ Проверка безопасности запроса

Выполнено: 0 / 4

Особенности работы с виртуальными таблицами

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

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

⚠️ Внимание: Параметры виртуальных таблиц (например, &НаДату) должны передаваться корректно. Ошибка в параметре может привести к тому, что виртуальная таблица вернет пустой результат, и МАКСИМУМ станет NULL.

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

Тонкости оптимизации СУБД

В SQL Server и PostgreSQL оптимизатор запросов может по-разному обрабатывать планы выполнения для агрегатов на виртуальных табелях. Иногда явное создание индекса по полям отбора дает прирост скорости до 50%.

Частые ошибки и способы их устранения

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

Другая распространенная ошибка — игнорирование прав доступа. Если у пользователя нет прав на чтение поля, по которому ищется максимум, запрос завершится ошибкой прав доступа, даже если на другие поля права есть. Всегда проверяйте РЛС (Ограничения на уровне записей), которые могут фильтровать данные до применения функции МАКСИМУМ.

⚠️ Внимание: РЛС применяется ДО выполнения запроса. Если ограничение скрывает все записи с максимальными значениями, функция вернет NULL или максимум из разрешенного подмножества, что может исказить бизнес-логику.

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

Можно ли использовать МАКСИМУМ для строк (тип Строка)?

Да, функция МАКСИМУМ применима к строковым полям. В этом случае она вернет строку, которая является последней в лексикографическом порядке сортировки. Например, для значений "Альфа", "Бета", "Вектор" результатом будет "Вектор".

Что быстрее: МАКСИМУМ в запросе или поиск в цикле?

Однозначно МАКСИМУМ в запросе. Поиск в цикле требует выгрузки всех данных из базы в память процесса 1С, что создает нагрузку на сеть и оперативную память. Агрегация на стороне СУБД передает только один байт результата.

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

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

Влияет ли тип базы данных (SQL Server, PostgreSQL) на работу МАКСИМУМ?

Синтаксис 1С унифицирован, но под капотом генерируются разные SQL-выражения. Логика работы идентична, но планы выполнения и скорость могут отличаться в зависимости от настроенных индексов в конкретной СУБД.