Как убрать дублирование групп при выводе иерархического справочника Номенклатура в 1С

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

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

Анализ проблемы: почему возникают дубли

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

Когда вы выполняете обход результата запроса методом Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам), система выдает нам сначала строку итога по иерархии (саму виртуальную группировку), а следом — детальную запись, если папка попала в результат запроса. Если в запросе не стоит фильтра на группы, папка выводится дважды: как "узел" дерева и как "лист" (строка данных). Проанализируем способы исправления этой ситуации.

Решение 1: Фильтрация групп в тексте запроса

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

Рассмотрим обновленный текст запроса:


ВЫБРАТЬ
    Спр.Артикул КАК Артикул,
    Спр.Код КАК Код,
    Спр.Ссылка КАК Ссылка,
    Спр.Наименование КАК Наименование,
    СУММА(ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0)) КАК Остаток,
    МАКСИМУМ(ЦеныНоменклатурыСрезПоследних.Цена) КАК Цена
ИЗ
    Справочник.Номенклатура КАК Спр
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
        ПО Спр.Ссылка = ТоварыНаСкладахОстатки.Номенклатура
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ВидЦены = &ВидЦен) КАК ЦеныНоменклатурыСрезПоследних
        ПО Спр.Ссылка = ЦеныНоменклатурыСрезПоследних.Номенклатура
ГДЕ
    Спр.ПометкаУдаления = ЛОЖЬ
    И Спр.ЭтоГруппа = ЛОЖЬ // Ключевое изменение: исключаем папки из детальных записей
СГРУППИРОВАТЬ ПО
    Спр.Артикул,
    Спр.Код,
    Спр.Ссылка,
    Спр.Наименование
УПОРЯДОЧИТЬ ПО
    Спр.Наименование
ИТОГИ ПО
    Ссылка ИЕРАРХИЯ

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

Решение 2: Программная обработка обхода результата

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

Система 1С предоставляет свойство ТипЗаписи у объекта ВыборкаИзРезультатаЗапроса. Нам нужно различать записи, которые являются итогами иерархии, и детальные записи элементов.


ВыборкаСсылка = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаСсылка.Следующий() Цикл
    
    // Если это итог по иерархии - выводим область оформления группы
    Если ВыборкаСсылка.ТипЗаписи() = ТипЗаписиЗапроса.ИтогПоИерархии Тогда
        Область = ОбластьСсылкаИерархия;
        Область.Параметры.Заполнить(ВыборкаСсылка);
        ТабДок.Вывести(Область, ВыборкаСсылка.Уровень());
        
    Иначе
        // Если это детальная запись, проверяем, не является ли элемент группой
        // В иерархических справочниках папка может попасть сюда как обычный элемент
        Если ВыборкаСсылка.Ссылка.ЭтоГруппа Тогда
            Продолжить; // Пропускаем дубликат
        КонецЕсли;
        
        Область = ОбластьСсылка;
        Область.Параметры.Заполнить(ВыборкаСсылка);
        ТабДок.Вывести(Область, ВыборкаСсылка.Уровень());
    КонецЕсли;
    
КонецЦикла;

В данном примере мы используем метод ТипЗаписи(). Это позволяет четко разделить оформление: для папок использовать одну область макета (например, с жирным шрифтом и заливкой), а для конкретных товаров — другую. Условие Если ВыборкаСсылка.Ссылка.ЭтоГруппа Тогда Продолжить; гарантирует, что папка не будет выведена повторно как обычная строка товара.

Решение 3: Использование Системы компоновки данных (СКД)

Как справедливо заметили участники обсуждения, для подобных задач "золотым стандартом" в современной разработке на платформе 8.3 является использование СКД. Рассмотрим преимущества этого подхода:

  1. Автоматическая иерархия: Вам достаточно выбрать поле Ссылка и в настройках группировки указать тип "Иерархия". СКД сама позаботится о том, чтобы данные не дублировались.
  2. Корректные ресурсы: Вы просто назначаете Остаток и Цена ресурсами. СКД правильно рассчитает их итоги по группам, используя функции Сумма и Среднее/Максимум соответственно.
  3. Гибкость: Пользователь сможет сам настраивать отборы, сортировки и дополнительные поля без изменения программного кода.

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

Рекомендации по оптимизации запроса

Выясним причину возможных замедлений. При работе с конфигурациями на базе БСП (как Розница 2.2), соединение физической таблицы справочника с виртуальными таблицами остатков и цен напрямую может работать медленно на больших объемах данных. Проанализируем, как сделать запрос более профессиональным:

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

← На главную