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