Как настроить отборы в СКД по детальным строкам и агрегатным показателям одновременно?

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

При разработке сложных отчетов на Системе Компоновки Данных (СКД), особенно в задачах анализа акций или условий продаж, программисты часто сталкиваются с необходимостью фильтровать данные на двух уровнях одновременно. Первый уровень — это детальные строки (например, количество конкретного товара в строке накладной), а второй — агрегатные значения (например, общая сумма или общее количество по всему документу). Рассмотрим ситуацию, когда при использовании сложных групп условий (И/ИЛИ) СКД выдает ошибку о том, что поле не обнаружено.

Почему возникает ошибка при компоновке запроса?

Проанализируем механизм работы СКД. Когда мы используем фигурные скобки {ГДЕ ...} во временных таблицах, компоновщик пытается «пробросить» пользовательские отборы непосредственно в текст SQL-запроса. Если отбор простой, система справляется успешно. Однако, если пользователь создает иерархическую группу условий (например, «ИЛИ»), в которой одно условие относится к первой временной таблице (детальные записи), а другое — к итоговой таблице (сгруппированные данные), возникает конфликт.

Выясним причину: СКД не может «разорвать» одну группу условий ИЛИ на разные части запроса. Она пытается наложить всю группу условий целиком на финальную выборку. Если поле из первой временной таблицы (например, КолвоШТПоСтроке) не было выбрано в конечном запросе или было «схлопнуто» группировкой СГРУППИРОВАТЬ ПО, генератор макета выдает ошибку на этапе КомпоновщикМакета.Выполнить. Поле физически отсутствует в итоговом наборе данных, и SQL-запрос не может быть построен.

Разбор исходного запроса

Посмотрим на пример запроса, который вызывает сложности. В первой временной таблице автор выбирает детальные данные из табличной части документа:


ВЫБРАТЬ
    РеализацияТовары.Ссылка КАК Реализация,
    РеализацияТовары.Номенклатура КАК Номенклатура,
    РеализацияТовары.Количество * РеализацияТовары.Коэффициент КАК КоличествоБЕ
ПОМЕСТИТЬ ВТ_Товары
{ГДЕ
    (РеализацияТовары.Количество * РеализацияТовары.Коэффициент) КАК КолвоШТПоСтроке}
ИЗ
    Документ.Реализация.Товары КАК РеализацияТовары
;

Затем данные группируются для получения итогов по документу:


ВЫБРАТЬ
    СУММА(ВТ_Товары.КоличествоБЕ) КАК КоличествоБЕ_сумма,
    ВТ_Товары.Реализация КАК Реализация
ПОМЕСТИТЬ ПредвГруппировка
ИЗ
    ВТ_Товары КАК ВТ_Товары
СГРУППИРОВАТЬ ПО
    ВТ_Товары.Реализация
;

Если наложить условие КоличествоБЕ_сумма = 10 ИЛИ КолвоШТПоСтроке = 2, система не сможет применить КолвоШТПоСтроке к таблице ПредвГруппировка, так как этого поля там больше нет.

Решение 1: Использование ресурсов СКД вместо группировки в запросе

Самый эффективный способ решить эту проблему — перенести задачу агрегации с уровня SQL-запроса на уровень самой СКД. Проанализируем преимущества этого подхода: когда мы вычисляем итоги через вкладку «Ресурсы», СКД сама понимает, где нужно использовать секцию WHERE (до группировки), а где — HAVING (после группировки).

  1. Уберем из запроса временную таблицу ПредвГруппировка и секцию СГРУППИРОВАТЬ ПО.
  2. Оставим в запросе только плоскую таблицу с детальными записями.
  3. На вкладке «Ресурсы» добавим поле КоличествоБЕ с выражением Сумма(КоличествоБЕ).
  4. В настройках отчета укажем группировку по полю Реализация.

В этом случае отбор по детальному полю КолвоШТПоСтроке будет работать как обычный фильтр строк, а отбор по ресурсу КоличествоБЕ превратится в условие на итоги. Это позволит пользователю строить любые сложные вложенные условия без ошибок.

Решение 2: Соединение детальных данных с итоговыми

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

  1. Формируем временную таблицу с агрегатами (как в исходном примере).
  2. В финальном запросе соединяем исходную таблицу ВТ_Товары с таблицей ПредвГруппировка по ключу Реализация.
  3. Выбираем все необходимые поля: и детальные, и суммированные.

Пример структуры финального запроса:


ВЫБРАТЬ
    ВТ_Товары.Реализация,
    ВТ_Товары.Номенклатура,
    ВТ_Товары.КоличествоБЕ КАК КолвоШТПоСтроке,
    ПредвГруппировка.КоличествоБЕ_сумма КАК КолвоВсегоПоДокументу
ИЗ
    ВТ_Товары КАК ВТ_Товары
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПредвГруппировка КАК ПредвГруппировка
    ПО ВТ_Товары.Реализация = ПредвГруппировка.Реализация
{ГДЕ
    ВТ_Товары.КоличествоБЕ КАК КолвоШТПоСтроке,
    ПредвГруппировка.КоличествоБЕ_сумма КАК КолвоВсегоПоДокументу}

Важный нюанс: при таком подходе в итоговой выборке строки будут дублироваться для каждой накладной (по количеству товаров в ней). Чтобы получить список уникальных накладных, в настройках СКД на вкладке «Группировки» следует использовать только поле Реализация, не выводя детальные записи.

Решение 3: Использование нескольких наборов данных

Рассмотрим еще один профессиональный метод — разделение данных на два Набора данных - запрос внутри одной схемы компоновки.

Первый набор данных назовем НаборСтроки (запрос по ТЧ товаров), второй — НаборИтоги (запрос с группировкой по документам). Свяжем их на закладке «Связи наборов данных» по полю Реализация.

Этот способ позволяет СКД максимально гибко управлять отборами. Условия, наложенные пользователем на поля первого набора, будут автоматически добавлены в его текст запроса. То же самое произойдет и со вторым набором. При этом логика объединения результатов (связь) останется за механизмом СКД, что исключает ошибки «Поле не обнаружено», так как каждое поле «живет» в своем контексте.

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

При реализации сложных отборов по акциям рекомендуется:

  1. Отказаться от жестких конструкций {ГДЕ ...} во вложенных временных таблицах, если вы планируете использовать эти же поля в итоговом отборе. Позвольте СКД самой управлять секцией ГДЕ в конечном запросе.
  2. Если используется программная компоновка (через КомпоновщикМакета), убедитесь, что все поля, участвующие в пользовательских настройках, доступны для выбора и не ограничены флагами в схеме.
  3. Помните, что использование СУММА() внутри запроса делает поле обычным числом для СКД. Чтобы СКД воспринимала его как агрегат (для условий HAVING), его нужно объявить ресурсом на соответствующей вкладке.

Проанализировав ситуацию, мы видим, что корень проблемы кроется в попытке объединить разнородные уровни данных в один плоский SQL-запрос с ручной группировкой. Переход к использованию ресурсов или связей наборов данных делает отчет гибким и устойчивым к любым пользовательским настройкам.

← На главную