При разработке отчетов в 1С начинающие программисты часто сталкиваются с ситуацией: в консоли запросов данные отображаются корректно, но при выводе в макет через программный код одно или несколько полей оказываются пустыми. Особенно часто это происходит, когда в коде используется обход по группировкам. Разберем детально, почему так происходит и как заставить "упрямое" поле появиться в вашем отчете.
Давайте проанализируем ситуацию. В представленном фрагменте кода автор использует метод Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам). Это ключевой момент. Когда мы выбираем данные с этим параметром, система строит иерархическую структуру на основании секции ИТОГИ вашего запроса.
Важно понимать: на уровне группировки (например, "Контрагент") доступны только те поля, которые:
ПО в секции ИТОГИ).СУММА(Остаток) или МАКСИМУМ(Дата)).Если поле МесяцевДоговора просто перечислено в блоке ВЫБРАТЬ, но не включено в расчет итогов, то при обходе группировок система "не знает", какое именно значение из множества детальных записей нужно показать на уровне итога. В результате в выборке по группировке это поле будет содержать NULL или пустое значение.
Если нам нужно вывести значение поля (например, число месяцев или номер договора) в ту же строку макета, где выводится заголовок группировки, нам необходимо явно указать системе, как агрегировать это значение. Рассмотрим пример изменения текста запроса:
// Было в запросе:
// ...
// ИТОГИ СУММА(Остаток) ПО Контрагент
// Стало (правильный вариант):
// ВЫБРАТЬ ..., МесяцевДоговора КАК МесяцевДоговора ...
// ...
// ИТОГИ СУММА(Остаток), МАКСИМУМ(МесяцевДоговора) ПО Контрагент
Использование функции МАКСИМУМ (или МИНИМУМ) для реквизитов, которые одинаковы для всей группировки, — это стандартный прием в 1С. Теперь при выполнении кода ВыборкаДок.МесяцевДоговора на уровне группировки вернет корректное число.
Если поле МесяцевДоговора является уникальным для каждой строки (детальной записи) и не должно выводиться в строке группировки, нам нужно изменить структуру циклов в коде. Разберем по шагам, как это работает:
ВыборкаКонтр = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаКонтр.Следующий() Цикл
// Здесь выводим строку группировки (например, Имя Контрагента)
// Поле "МесяцевДоговора" здесь будет недоступно без агрегатов!
ВыборкаДетальныеЗаписи = ВыборкаКонтр.Выбрать(); // Выбираем записи внутри группы
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
// А вот здесь доступны ВСЕ поля из блока ВЫБРАТЬ
ОбластьСтрока.Параметры.СрокЛизинга = ВыборкаДетальныеЗаписи.МесяцевДоговора;
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
КонецЦикла;
В этом случае мы сначала получаем "узел" дерева (группировку), а затем "листья" (детальные записи). Поле, которое не выводилось ранее, теперь будет доступно в ВыборкаДетальныеЗаписи.
Как заметил автор темы в сообщении №6, если убрать ПоГруппировкам, поле начинает выводиться. Это происходит потому, что при использовании ОбходРезультатаЗапроса.Прямой (используется по умолчанию, если не указать параметр), система игнорирует итоги и просто выдает плоскую таблицу, в точности как в консоли запросов.
Если вашему отчету не нужна древовидная структура (сворачивание строк, итоги по иерархии), используйте простой обход:
Выборка = РезультатЗапроса.Выбрать(); // Прямой обход
Пока Выборка.Следующий() Цикл
// Доступны все поля детальных записей
Область.Параметры.СрокЛизинга = Выборка.МесяцевДоговора;
ТабДок.Вывести(Область);
КонецЦикла;
Проанализируем фрагмент кода из сообщения №9: ВыборкаДок.Регистратор.Договор.Номер. В 1С это считается "плохим тоном" и серьезной ошибкой производительности.
Почему это плохо? Каждый раз, когда вы обращаетесь через точку от ссылки (Регистратор -> Договор -> Номер), платформа выполняет отдельный неявный запрос к базе данных для получения этих данных. Если в отчете 1000 строк, система может выполнить тысячи лишних микро-запросов, что сильно замедлит работу.
Как правильно? Все нужные данные следует получать сразу в тексте запроса. Давайте посмотрим, как оптимизировать этот фрагмент:
// В тексте запроса:
// ВЫБРАТЬ
// ДоговорЛизинга.Номер КАК НомерДоговора,
// ДоговорЛизинга.СтоимостьИмущества КАК СтоимостьИмущества,
// ...
// В коде вывода:
ОбластьСтрокаОсновной1.Параметры.НомерДоговора = ВыборкаДок.НомерДоговора;
ОбластьСтрокаОсновной1.Параметры.СтоимостьИмущества = ВыборкаДок.СтоимостьИмущества;
Выяснив причину и применив один из предложенных способов (добавление агрегата в ИТОГИ или использование вложенной выборки), вы сможете корректно вывести любые поля в макет, сохраняя при этом иерархическую структуру отчета.