Приветствуем всех разработчиков 1С! Сегодня мы разберем классическую, но довольно коварную проблему, с которой часто сталкиваются при проектировании сложных отчетов на Системе компоновки данных (СКД). Представьте ситуацию: вы создали отличный отчет для сверки данных (например, сравниваете обороты бухгалтерского учета с данными раздельного учета НДС). Вы написали запрос, наложили условие связи, добавили фильтр, проверяющий расхождение сумм, и в консоли запросов все работает идеально. Но стоит пользователю в режиме предприятия зайти в настройки, отключить или добавить пару полей, как отчет ломается: группировки «слетают», а условие фильтрации расхождений просто перестает работать. Выясним причину этого поведения системы и подробно разберем, как решить эту проблему раз и навсегда.
Проанализируем ситуацию на примере реального запроса. Изначально разработчик строит пакетный запрос, где на последнем этапе пытается объединить данные двух регистров, сгруппировать их по аналитике (счет, организация, подразделение, субконто) и наложить условие:
ВЫБРАТЬ
ВТ_Итог.Счет КАК Счет,
ВТ_Итог.Организация КАК Организация,
ВТ_Итог.Подразделение КАК Подразделение,
ВТ_Итог.Субконто1 КАК Субконто1,
ВТ_Итог.Субконто2 КАК Субконто2,
ВТ_Итог.Субконто3 КАК Субконто3,
ВТ_Итог.СуммаОборотДт КАК СуммаОборотДт,
ВТ_Итог.СуммаРаздельногоУчетаНДС КАК СуммаРаздельногоУчетаНДС
ИЗ
ВТ_Итог КАК ВТ_Итог
ГДЕ
ВТ_Итог.СуммаОборотДт <> ВТ_Итог.СуммаРаздельногоУчетаНДС
Или использует секцию ИМЕЮЩИЕ непосредственно при группировке детальных записей:
ИМЕЮЩИЕ
СУММА(ВТ_Суммы.СуммаРаздельногоУчетаНДС) <> СУММА(ВТ_Суммы.СуммаОборотДт)
Когда этот запрос помещается в СКД с включенным флагом «Автозаполнение», система начинает управлять текстом запроса динамически. СКД пытается оптимизировать запрос под те поля, которые пользователь выбрал в настройках компоновщика на форме. Если пользователь убирает из выбранных полей, например, Субконто1 или Подразделение, СКД делает следующее:
ВЫБРАТЬ.СГРУППИРОВАТЬ ПО во всех временных таблицах пакета, где это возможно.В этот момент и происходит сбой. Если условие фильтрации сумм жестко зашито в секцию ГДЕ или ИМЕЮЩИЕ внутри SQL-запроса, СУБД выполняет расчет разницы на уровне тех группировок, которые прописаны в базе данных (до субконто). Когда пользователь отключает эти поля на форме, СКД выводит сгруппированный результат без учета отключенных полей, но математический отбор уже отсек строки на более детальном уровне! В итоге мы получаем искаженные данные или полное отсутствие фильтрации.
Также негативную роль играют фигурные скобки {} в запросе. Если вы помещаете условие в фигурные скобки, например: {ГДЕ (ВТ_Итог.СуммаРаздельногоУчетаНДС <> ВТ_Итог.СуммаОборотДт) КАК ОтборПоСумме}, то при невыбранном хотя бы одном поле, участвующем в условии, СКД считает это условие необязательным и просто вырезает его из итогового SQL-запроса.
Рассмотрим три надежных способа решения этой проблемы, которые соответствуют лучшим практикам разработки в среде 1С.
Самый правильный и архитектурно верный способ — отказаться от группировки сумм и наложения условий расхождения непосредственно внутри текста запроса. Позвольте СКД делать то, для чего она создана: агрегировать данные и накладывать фильтры на уровне схемы компоновки.
Разберем этот способ по шагам:
СГРУППИРОВАТЬ ПО и условия ИМЕЮЩИЕ или ГДЕ, сравнивающие суммы. Запрос должен возвращать «плоскую» детальную таблицу со всеми необходимыми аналитиками и детальными суммами.СуммаОборотДт и СуммаРаздельногоУчетаНДС. В качестве выражения для обоих полей укажите функцию Сумма(СуммаОборотДт) и Сумма(СуммаРаздельногоУчетаНДС) соответственно.СуммаОборотДт <> СуммаРаздельногоУчетаНДС в общих настройках отчета, СКД применит его к детальным записям (в секции ГДЕ), что приведет к неверному результату. Чтобы фильтрация происходила после группировки данных:
СуммаОборотДт Не равно СуммаРаздельногоУчетаНДС.При таком подходе СКД сначала динамически сгруппирует данные по тем полям, которые выбрал пользователь, затем рассчитает итоги по ресурсам для этой группировки, и только после этого отсечет строки, где суммы сошлись. Данный метод работает безотказно при любых манипуляциях пользователя со структурой отчета.
Если вы хотите предоставить пользователю возможность самостоятельно управлять отбором по расхождениям прямо из пользовательских настроек, отлично подойдет вариант с созданием вычисляемого поля.
Разберем данный алгоритм:
РазницаСумм. В качестве выражения укажите: ЕСТЬNULL(СуммаОборотДт, 0) - ЕСТЬNULL(СуммаРаздельногоУчетаНДС, 0).РазницаСумм ресурсом. Выражение для расчета: Сумма(РазницаСумм).РазницаСумм Не равно 0. Для удобства пользователя этот отбор можно включить в состав пользовательских настроек с быстрым доступом.Этот способ крайне изящен, так как пользователю не нужно вникать в сравнение двух разных полей — достаточно включить один флаг отбора по полю РазницаСумм.
Иногда возникают ситуации, когда логика запроса настолько сложна (например, используются специфические соединения или виртуальные таблицы с жесткими параметрами), что «сгладить» запрос до детальных записей невозможно. В таком случае нам придется отключить стандартный оптимизатор СКД и настроить схему вручную.
Выполните следующие действия:
{}, но делайте это осознанно. Например, секцию описания полей компоновки в запросе можно оформить так:
ВЫБРАТЬ
ВТ_Итог.Счет КАК Счет,
ВТ_Итог.Организация КАК Организация,
ВТ_Итог.СуммаОборотДт КАК СуммаОборотДт,
ВТ_Итог.СуммаРаздельногоУчетаНДС КАК СуммаРаздельногоУчетаНДС
{ВЫБРАТЬ
Счет.*,
Организация.*,
СуммаОборотДт,
СуммаРаздельногоУчетаНДС}
ИЗ
ВТ_Итог КАК ВТ_Итог
{ГДЕ
ВТ_Итог.Счет.*,
ВТ_Итог.Организация.*}
При отключенном автозаполнении структура вашего пакета запросов останется стабильной, и СУБД гарантированно вернет ожидаемый результат, однако этот способ требует от разработчика высокой квалификации и ручного прописывания всех связей и ролей полей.
Мы проанализировали проблему динамического изменения состава полей в СКД и выяснили, что попытка жесткого наложения условий сравнения внутри SQL-запроса противоречит самой концепции Системы компоновки данных. Перенос фильтрации расхождений на уровень ресурсов (Способ 1) или использование вычисляемых полей (Способ 2) гарантируют стабильную работу отчета при любых действиях пользователя в режиме предприятия. Рекомендуем использовать именно эти подходы в вашей ежедневной практике разработки на платформе 1С:Предприятие!