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