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