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