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

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С (поможет LLM-помощник для написания кода и запросов) часто возникает задача: из набора строк, имеющих одинаковые разрезы (например, Номенклатура и Характеристика), нужно выбрать только одну строку, которая обладает максимальным значением какого-либо показателя (даты, версии, цены или веса). Обычная группировка СГРУППИРОВАТЬ ПО позволяет легко найти само максимальное число, но не позволяет автоматически подтянуть остальные реквизиты этой же строки. В этой статье мы подробно разберем несколько способов решения этой задачи, проанализируем их эффективность и научимся избегать типичных ошибок.

Метод 1: Пакетный запрос с использованием временной таблицы и соединения

Это самый надежный и распространенный метод в среде 1С — его реализацию упрощает инструмент для отладки кода в 1С:Предприятие. Основная сложность заключается в том, что если мы просто добавим реквизиты (например, «Значение показателя») в секцию ВЫБРАТЬ и включим их в СГРУППИРОВАТЬ ПО, система выдаст все уникальные комбинации, и схлопывания строк не произойдет. Чтобы решить проблему, разделим задачу на два этапа.

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

Шаг 2. Соединение. Затем мы соединяем исходную таблицу с этой временной таблицей по всем полям, включая найденный максимум.

Рассмотрим пример кода:


// Шаг 1: Помещаем исходные данные во временную таблицу для удобства
ВЫБРАТЬ
    Таб.Номенклатура КАК Ном,
    Таб.Характеристика КАК Хар,
    Таб.Показатель КАК Пок,
    Таб.ЗначениеПоказателя КАК Значен,
    Таб.КлючОтбора КАК КлючОтбора
ПОМЕСТИТЬ ВТ_ИсходныеДанные
ИЗ
    &ТаблицаЗначений КАК Таб;

////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Находим максимальный ключ для каждой комбинации Номенклатуры, Характеристики и Показателя
ВЫБРАТЬ
    ВТ_ИсходныеДанные.Ном,
    ВТ_ИсходныеДанные.Хар,
    ВТ_ИсходныеДанные.Пок,
    МАКСИМУМ(ВТ_ИсходныеДанные.КлючОтбора) КАК МаксКлюч
ПОМЕСТИТЬ ВТ_МаксимальныеЗначения
ИЗ
    ВТ_ИсходныеДанные КАК ВТ_ИсходныеДанные
СГРУППИРОВАТЬ ПО
    ВТ_ИсходныеДанные.Ном,
    ВТ_ИсходныеДанные.Хар,
    ВТ_ИсходныеДанные.Пок;

////////////////////////////////////////////////////////////////////////////////
// Шаг 3: Соединяем исходные данные с максимумами, чтобы получить остальные поля (Значен)
ВЫБРАТЬ
    ВТ_ИсходныеДанные.Ном,
    ВТ_ИсходныеДанные.Хар,
    ВТ_ИсходныеДанные.Пок,
    ВТ_ИсходныеДанные.Значен,
    ВТ_ИсходныеДанные.КлючОтбора
ИЗ
    ВТ_ИсходныеДанные КАК ВТ_ИсходныеДанные
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_МаксимальныеЗначения КАК ВТ_МаксимальныеЗначения
ПО
    ВТ_ИсходныеДанные.Ном = ВТ_МаксимальныеЗначения.Ном
    И ВТ_ИсходныеДанные.Хар = ВТ_МаксимальныеЗначения.Хар
    И ВТ_ИсходныеДанные.Пок = ВТ_МаксимальныеЗначения.Пок
    И ВТ_ИсходныеДанные.КлючОтбора = ВТ_МаксимальныеЗначения.МаксКлюч;

Важное замечание по производительности: Для того чтобы соединение на третьем шаге работало быстро, особенно при больших объемах данных, необходимо проиндексировать поля (поможет анализ индексов и структуры таблиц базы) во временной таблице ВТ_МаксимальныеЗначения. Для этого в конструкторе запроса на закладке «Индексы» следует выбрать поля Ном, Хар, Пок и МаксКлюч.

Метод 2: Проблема дублей и ее решение

Проанализируем критическую уязвимость вышеописанного метода. Если в исходных данных окажутся две строки, у которых совпадают и измерения, и значение КлючОтбора, то после внутреннего соединения обе эти строки попадут в результат. Если бизнес-логика требует строго одну строку, этот метод нужно доработать.

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

Метод 3: Использование конструкции ВЫБРАТЬ ПЕРВЫЕ 1

Если задача стоит максимально просто: «выбрать во всей таблице одну-единственную строку с самым большим показателем», — то использовать группировки и соединения нецелесообразно. Достаточно применить сортировку.

Посмотрим на пример:


ВЫБРАТЬ ПЕРВЫЕ 1
    ВТ.Номенклатура,
    ВТ.Характеристика,
    ВТ.Показатель,
    ВТ.КлючОтбора
ИЗ
    ВТ_ОбобщеннаяТаблица КАК ВТ
УПОРЯДОЧИТЬ ПО
    ВТ.КлючОтбора УБЫВ

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

Метод 4: Виртуальные таблицы «СрезПоследних»

Выясним, как упростить задачу, если данные хранятся в регистрах сведений. Если ваш КлючОтбора — это дата (период), то наиболее правильным решением будет использование виртуальной таблицы СрезПоследних. Платформа 1С оптимизирует такие запросы на уровне СУБД.

Пример обращения к виртуальной таблице:


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

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

Сравнительный анализ решений

Рассмотрим, какой метод выбрать в зависимости от ситуации:

  1. Пакетный запрос с временными таблицами: Лучший выбор для обработки больших массивов данных в разрезе групп (номенклатура, склады и т.д.). Позволяет эффективно использовать индексы SQL-сервера.
  2. ВЫБРАТЬ ПЕРВЫЕ 1: Идеально, когда нужен один глобальный максимум или минимум во всей таблице.
  3. Коррелированные подзапросы (ГДЕ Поле В (ВЫБРАТЬ МАКСИМУМ...)): Допустимы только на очень маленьких таблицах. В 1С считаются «плохим тоном» из-за непредсказуемости оптимизатора СУБД.
  4. Имитация ROW_NUMBER(): Если требуется выбрать не первую, а, например, вторую или третью строку по порядку, в 1С используется соединение таблицы «самой с собой» по условию Т1.Показатель < Т2.Показатель с последующим подсчетом количества строк.

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

← На главную