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