Как настроить отбор по вычисляемому полю (ресурсу) в отчете на СКД, чтобы он влиял на общий итог?

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

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

Мы рассмотрим ситуацию на примере типового отчета "Размещение товаров на адресном складе" в конфигурации 1С:Комплексная автоматизация редакции 2. В этом отчете есть вычисляемое поле "% заполнения" (или ДоляЗанятогоОбъема), по которому требуется установить отбор.

В чем причина некорректной работы отбора?

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

Если же мы пытаемся установить отбор на вычисляемое поле на уровне всего отчета (как "главный отбор"), то система компоновки данных пытается поместить это условие отбора в текст запроса к источнику данных. В этом случае отбор применяется к детальным записям. Но вычисляемое поле, такое как "% заполнения", как правило, рассчитывается на уровне группировок (например, как отношение суммы занятого объема к сумме общего объема по группе ячеек). Для отдельных детальных записей (например, одной строки регистра, описывающей один товар в одной ячейке), это поле может иметь нулевое или неопределенное значение, поскольку его смысл проявляется только после агрегации. В результате, когда система пытается применить отбор по такому полю к детальным записям, условие отбора по нему не выполняется или дает ложный результат для большинства записей, и отчет может ничего не вывести.

Ключевой момент, который нам необходимо понять: для того чтобы отбор по вычисляемому полю влиял на общий итог, необходимо, чтобы это поле было доступно для фильтрации на более раннем этапе обработки данных, то есть в запросе, до того, как будут сформированы агрегированные значения и общие итоги.

Как настроить отбор по вычисляемому полю, чтобы он влиял на общий итог?

Существует несколько подходов к решению данной задачи. Мы подробно рассмотрим каждый из них.

  1. Перенос расчета поля в запрос набора данных

    Это наиболее надежный и рекомендуемый способ. Суть его заключается в том, чтобы включить расчет поля "% заполнения" (или ДоляЗанятогоОбъема) непосредственно в текст запроса, который формирует набор данных для СКД. Если это поле будет рассчитано на уровне детальных записей запроса или на уровне промежуточных группировок внутри самого запроса, то оно станет обычным полем набора данных. Тогда оно будет доступно для отбора на уровне всего отчета, и этот отбор будет влиять на все последующие агрегации и общий итог.

    Для этого нам потребуется перевести логику расчета "% заполнения" на язык запросов 1С. Обычно это означает использование агрегатных функций (СУММА) и, возможно, временных таблиц или вложенных запросов, чтобы получить необходимые для расчета данные. Например, если "% заполнения" рассчитывается как отношение СУММА(ЗанятыйОбъем) / СУММА(ОбщийОбъем), нам нужно убедиться, что оба эти компонента доступны в запросе для каждой строки или группы, по которой мы хотим сделать отбор.

    Рассмотрим пример, как мы могли бы рассчитать ДоляЗанятогоОбъема прямо в запросе, предполагая, что нам нужно получить процент заполнения для каждой области хранения, а затем по этому проценту отбирать. Это потребует, чтобы все данные, нужные для расчета процента (занятый объем и общий объем ячеек), были доступны и агрегированы в запросе.

    
    // Предположим, что мы хотим получить процент заполнения для каждой области хранения.
    // Для этого нам сначала нужно посчитать суммарный занятый и общий объем по каждой области.
    
    ВЫБРАТЬ
        СкладскиеЯчейки.ОбластьХранения КАК ОбластьХранения,
        СУММА(ТоварыВЯчейках.Количество * ТоварыВЯчейках.ОбъемЕдиницы) КАК ЗанятыйОбъемПоОбласти,
        СУММА(СкладскиеЯчейки.ОбъемЯчейки) КАК ОбщийОбъемПоОбласти
    ПОМЕСТИТЬ ВТ_ОбъемыПоОбластям
    ИЗ
        РегистрНакопления.ТоварыВЯчейках КАК ТоварыВЯчейках
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.СкладскиеЯчейки КАК СкладскиеЯчейки
        ПО ТоварыВЯчейках.Ячейка = СкладскиеЯчейки.Ссылка
    СГРУППИРОВАТЬ ПО
        СкладскиеЯчейки.ОбластьХранения
    ;
    
    ////////////////////////////////////////////////////////////////////////////////
    ВЫБРАТЬ
        ВТ_ОбъемыПоОбластям.ОбластьХранения,
        ВТ_ОбъемыПоОбластям.ЗанятыйОбъемПоОбласти,
        ВТ_ОбъемыПоОбластям.ОбщийОбъемПоОбласти,
        ЕСТЬNULL(ВТ_ОбъемыПоОбластям.ЗанятыйОбъемПоОбласти * 100 / ВТ_ОбъемыПоОбластям.ОбщийОбъемПоОбласти, 0) КАК ДоляЗанятогоОбъемаВЗапросе
    ИЗ
        ВТ_ОбъемыПоОбластям КАК ВТ_ОбъемыПоОбластям
    

    В этом примере мы сначала агрегируем данные во временную таблицу ВТ_ОбъемыПоОбластям, а затем во втором запросе рассчитываем ДоляЗанятогоОбъемаВЗапросе. Это поле будет доступно как обычное поле набора данных СКД, и мы сможем установить по нему отбор на уровне всего отчета, например, ДоляЗанятогоОбъемаВЗапросе >= 50. Такой отбор будет применен к данным, влияющим на итоговые расчеты.

  2. Использование вспомогательного поля в запросе для отбора

    Если полный расчет поля в запросе представляется слишком сложным или нецелесообразным для каждого детального элемента, мы можем создать в запросе вспомогательное булево или числовое поле, которое будет сигнализировать о соответствии записи условию отбора по "% заполнения". По сути, мы переносим само условие отбора в запрос.

    Например, если нам нужно отобрать области хранения, у которых "% заполнения" превышает определенный порог, мы можем добавить в запрос такую конструкцию:

    
    ВЫБРАТЬ
        СкладскиеЯчейки.ОбластьХранения,
        // Другие поля...
        ВЫБОР
            КОГДА ЕСТЬNULL(СУММА(ТоварыВЯчейках.Количество * ТоварыВЯчейках.ОбъемЕдиницы) * 100 / СУММА(СкладскиеЯчейки.ОбъемЯчейки), 0) >= &МинимальныйПроцентЗаполнения
                ТОГДА ИСТИНА
            ИНАЧЕ ЛОЖЬ
        КОНЕЦ КАК УдовлетворяетУсловиюОтбораПоПроценту
    ИЗ
        РегистрНакопления.ТоварыВЯчейках КАК ТоварыВЯчейках
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.СкладскиеЯчейки КАК СкладскиеЯчейки
        ПО ТоварыВЯчейках.Ячейка = СкладскиеЯчейки.Ссылка
    СГРУППИРОВАТЬ ПО
        СкладскиеЯчейки.ОбластьХранения
        // Другие группировки...
    

    В данном случае, мы сгруппировали данные по ОбластьХранения и рассчитали условие для процента заполнения внутри запроса. Затем, в настройках СКД, мы устанавливаем отбор по этому новому полю: УдовлетворяетУсловиюОтбораПоПроценту = ИСТИНА. Отбор будет работать корректно, так как условие фильтрации уже встроено в запрос.

  3. Применение функции ВычислитьВыражение

    Функция ВычислитьВыражение в СКД позволяет вычислять выражения для различных уровней группировок или для общего итога. Она может быть полезна для более сложных расчетов, включая процентные соотношения, которые нужно отобразить в отчете. Однако, ее использование для прямого отбора, который должен влиять на итоговые суммы, имеет ограничения.

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

  4. Использование вложенных запросов и временных таблиц

    В сложных случаях, особенно когда данные объединяются из нескольких источников или требуют многоступенчатой обработки перед расчетом процента, можно использовать вложенные запросы или временные таблицы. Это позволяет нам выполнить предварительный расчет необходимых полей (в нашем случае - ЗанятыйОбъем и ОбщийОбъем, а затем и их отношение) и сделать их доступными для основного запроса, который будет использоваться в наборе данных СКД. Это, по сути, более продвинутый вариант первого подхода "Перенос расчета поля в запрос набора данных".

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

    
    // Пример использования нескольких временных таблиц для расчета и отбора
    // Шаг 1: Собираем детальные данные по занятому объему в каждой ячейке
    ВЫБРАТЬ
        ТоварыВЯчейках.Ячейка КАК Ячейка,
        СУММА(ТоварыВЯчейках.Количество * ТоварыВЯчейках.ОбъемЕдиницы) КАК ЗанятыйОбъемВЯчейке
    ПОМЕСТИТЬ ВТ_ЗанятыйОбъемЯчеек
    ИЗ
        РегистрНакопления.ТоварыВЯчейках КАК ТоварыВЯчейках
    СГРУППИРОВАТЬ ПО
        ТоварыВЯчейках.Ячейка
    ;
    
    ////////////////////////////////////////////////////////////////////////////////
    // Шаг 2: Соединяем занятый объем с общей информацией по ячейкам и областям
    ВЫБРАТЬ
        СкладскиеЯчейки.ОбластьХранения КАК ОбластьХранения,
        ВТ_ЗанятыйОбъемЯчеек.ЗанятыйОбъемВЯчейке КАК ЗанятыйОбъемВЯчейке,
        СкладскиеЯчейки.ОбъемЯчейки КАК ОбщийОбъемЯчейки
    ПОМЕСТИТЬ ВТ_ДанныеПоЯчейкамСОбластями
    ИЗ
        Справочник.СкладскиеЯчейки КАК СкладскиеЯчейки
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ЗанятыйОбъемЯчеек КАК ВТ_ЗанятыйОбъемЯчеек
        ПО СкладскиеЯчейки.Ссылка = ВТ_ЗанятыйОбъемЯчеек.Ячейка
    ;
    
    ////////////////////////////////////////////////////////////////////////////////
    // Шаг 3: Агрегируем данные по областям хранения и рассчитываем процент заполнения
    ВЫБРАТЬ
        ВТ_ДанныеПоЯчейкамСОбластями.ОбластьХранения,
        СУММА(ЕСТЬNULL(ВТ_ДанныеПоЯчейкамСОбластями.ЗанятыйОбъемВЯчейке, 0)) КАК СуммарныйЗанятыйОбъем,
        СУММА(ВТ_ДанныеПоЯчейкамСОбластями.ОбщийОбъемЯчейки) КАК СуммарныйОбщийОбъем,
        ЕСТЬNULL(СУММА(ЕСТЬNULL(ВТ_ДанныеПоЯчейкамСОбластями.ЗанятыйОбъемВЯчейке, 0)) * 100 / СУММА(ВТ_ДанныеПоЯчейкамСОбластями.ОбщийОбъемЯчейки), 0) КАК ДоляЗанятогоОбъемаДляОтбора
    ИЗ
        ВТ_ДанныеПоЯчейкамСОбластями КАК ВТ_ДанныеПоЯчейкамСОбластями
    СГРУППИРОВАТЬ ПО
        ВТ_ДанныеПоЯчейкамСОбластями.ОбластьХранения
    

    Полученное поле ДоляЗанятогоОбъемаДляОтбора в последнем запросе будет доступно для отбора на уровне всего отчета, и его фильтрация будет корректно влиять на общие итоги, поскольку расчеты проведены до передачи данных в основной механизм агрегации СКД.

  5. Учет версии платформы 1С

    При работе с СКД всегда стоит обращать внимание на используемую версию платформы 1С. В некоторых более старых версиях, например, до 8.3.18, могли существовать определенные особенности в работе отборов в запросах, особенно с объединениями или сложными группировками. Эти особенности могли приводить к некорректному поведению или непредсказуемым результатам.

    Если вы сталкиваетесь с аномальным поведением отборов, даже после применения описанных выше методов, мы рекомендуем убедиться, что используете актуальную версию платформы 1С. Обновление платформы или работа вне режима совместимости (если это применимо к вашей конфигурации) часто может решить подобные проблемы, обеспечивая более предсказуемое и корректное поведение СКД.

Таким образом, для того чтобы отбор по вычисляемому полю влиял на общий итог, мы должны стремиться сделать это поле частью основного запроса, который формирует набор данных для СКД. Это позволяет системе применить фильтрацию на раннем этапе обработки данных, до того, как будут сформированы агрегированные значения и общие итоги, обеспечивая таким образом, что отбор будет влиять на все последующие расчеты и на итоговые суммы в отчете.

← На главную