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