Почему поле запроса не выводится в отчет при использовании группировок?

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

При разработке отчетов в 1С начинающие программисты часто сталкиваются с ситуацией: в консоли запросов данные отображаются корректно, но при выводе в макет через программный код одно или несколько полей оказываются пустыми. Особенно часто это происходит, когда в коде используется обход по группировкам. Разберем детально, почему так происходит и как заставить "упрямое" поле появиться в вашем отчете.

Анализируем причину проблемы

Давайте проанализируем ситуацию. В представленном фрагменте кода автор использует метод Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам). Это ключевой момент. Когда мы выбираем данные с этим параметром, система строит иерархическую структуру на основании секции ИТОГИ вашего запроса.

Важно понимать: на уровне группировки (например, "Контрагент") доступны только те поля, которые:

  1. Являются полями самой группировки (указаны после слова ПО в секции ИТОГИ).
  2. Являются агрегатными функциями (например, СУММА(Остаток) или МАКСИМУМ(Дата)).

Если поле МесяцевДоговора просто перечислено в блоке ВЫБРАТЬ, но не включено в расчет итогов, то при обходе группировок система "не знает", какое именно значение из множества детальных записей нужно показать на уровне итога. В результате в выборке по группировке это поле будет содержать NULL или пустое значение.

Вариант решения №1: Использование агрегатных функций в итогах

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


// Было в запросе:
// ...
// ИТОГИ СУММА(Остаток) ПО Контрагент

// Стало (правильный вариант):
// ВЫБРАТЬ ..., МесяцевДоговора КАК МесяцевДоговора ...
// ...
// ИТОГИ СУММА(Остаток), МАКСИМУМ(МесяцевДоговора) ПО Контрагент

Использование функции МАКСИМУМ (или МИНИМУМ) для реквизитов, которые одинаковы для всей группировки, — это стандартный прием в 1С. Теперь при выполнении кода ВыборкаДок.МесяцевДоговора на уровне группировки вернет корректное число.

Вариант решения №2: Вложенный обход детальных записей

Если поле МесяцевДоговора является уникальным для каждой строки (детальной записи) и не должно выводиться в строке группировки, нам нужно изменить структуру циклов в коде. Разберем по шагам, как это работает:


ВыборкаКонтр = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаКонтр.Следующий() Цикл
    // Здесь выводим строку группировки (например, Имя Контрагента)
    // Поле "МесяцевДоговора" здесь будет недоступно без агрегатов!
    
    ВыборкаДетальныеЗаписи = ВыборкаКонтр.Выбрать(); // Выбираем записи внутри группы
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        // А вот здесь доступны ВСЕ поля из блока ВЫБРАТЬ
        ОбластьСтрока.Параметры.СрокЛизинга = ВыборкаДетальныеЗаписи.МесяцевДоговора;
        ТабДок.Вывести(ОбластьСтрока);
    КонецЦикла;
КонецЦикла;

В этом случае мы сначала получаем "узел" дерева (группировку), а затем "листья" (детальные записи). Поле, которое не выводилось ранее, теперь будет доступно в ВыборкаДетальныеЗаписи.

Вариант решения №3: Прямой обход (без иерархии)

Как заметил автор темы в сообщении №6, если убрать ПоГруппировкам, поле начинает выводиться. Это происходит потому, что при использовании ОбходРезультатаЗапроса.Прямой (используется по умолчанию, если не указать параметр), система игнорирует итоги и просто выдает плоскую таблицу, в точности как в консоли запросов.

Если вашему отчету не нужна древовидная структура (сворачивание строк, итоги по иерархии), используйте простой обход:


Выборка = РезультатЗапроса.Выбрать(); // Прямой обход
Пока Выборка.Следующий() Цикл
    // Доступны все поля детальных записей
    Область.Параметры.СрокЛизинга = Выборка.МесяцевДоговора;
    ТабДок.Вывести(Область);
КонецЦикла;

Важное замечание по оптимизации (Разыменование ссылок)

Проанализируем фрагмент кода из сообщения №9: ВыборкаДок.Регистратор.Договор.Номер. В 1С это считается "плохим тоном" и серьезной ошибкой производительности.

Почему это плохо? Каждый раз, когда вы обращаетесь через точку от ссылки (Регистратор -> Договор -> Номер), платформа выполняет отдельный неявный запрос к базе данных для получения этих данных. Если в отчете 1000 строк, система может выполнить тысячи лишних микро-запросов, что сильно замедлит работу.

Как правильно? Все нужные данные следует получать сразу в тексте запроса. Давайте посмотрим, как оптимизировать этот фрагмент:


// В тексте запроса:
// ВЫБРАТЬ
//    ДоговорЛизинга.Номер КАК НомерДоговора,
//    ДоговорЛизинга.СтоимостьИмущества КАК СтоимостьИмущества,
//    ...

// В коде вывода:
ОбластьСтрокаОсновной1.Параметры.НомерДоговора = ВыборкаДок.НомерДоговора;
ОбластьСтрокаОсновной1.Параметры.СтоимостьИмущества = ВыборкаДок.СтоимостьИмущества;

Выяснив причину и применив один из предложенных способов (добавление агрегата в ИТОГИ или использование вложенной выборки), вы сможете корректно вывести любые поля в макет, сохраняя при этом иерархическую структуру отчета.

← На главную