Приветствуем вас, уважаемые коллеги! Каждый разработчик в среде 1С:Предприятие рано или поздно сталкивается с классической проблемой Системы компоновки данных (СКД): в консоли запросов данные рассчитываются идеально, а при выводе отчета в СКД числовые показатели (ресурсы) внезапно умножаются или складываются некорректно. Сегодня мы подробно разберем, почему возникает этот неприятный эффект, проанализируем внутренние механизмы СКД и рассмотрим четыре надежных способа решения этой задачи.
Представим типовую бизнес-логику: на производстве выпускается готовая продукция. Данные фиксируются в регистре накопления. При проведении документа выпуска в регистр записывается информация о произведенном товаре и одновременно о сырье (комплектующих), которое ушло на его изготовление. Таким образом, на одну единицу выпущенной продукции приходится несколько строк списанного сырья (классическая связь «один-ко-многим»).
Если мы попытаемся соединить эти данные внутри одного запроса, СУБД выполнит операцию LEFT JOIN или INNER JOIN. На уровне строк это будет выглядеть следующим образом:
Когда этот запрос выполняется в консоли с жесткой группировкой по продукции, мы можем применить функцию МАКСИМУМ к количеству продукции, и итог покажет правильное значение — 1 шт. Но как только мы переносим этот запрос в СКД и пользователь выводит детальные записи (включая сырье и регистратор), СКД динамически перестраивает структуру запроса. При попытке рассчитать общие итоги по ресурсу «Количество продукции» СКД выполнит стандартное суммирование Сумма(КоличествоПродукции) по всем строкам выборки. В результате наш единственный выпущенный шкаф просуммируется трижды, и в отчете мы увидим выпуск в объеме 3 шт. вместо 1 шт. Это и есть классическое «задвоение» или размножение итогов.
Давайте разберем по шагам, как решить эту проблему профессиональными методами разработки.
Этот метод считается наиболее чистым и архитектурно правильным с точки зрения платформы 1С. Вместо того чтобы пытаться соединить разнородные по детальности данные в одном тяжелом SQL-запросе, мы поручим эту задачу самой СКД.
Мы создадим два независимых набора данных типа «Запрос».
Шаг 1. Создаем первый набор данных. Назовем его НаборДанныхВыпуск. Этот запрос будет выбирать исключительно уникальные данные по выпуску продукции без какой-либо информации о сырье.
ВЫБРАТЬ
ОборотыПродукции.Регистратор КАК Регистратор,
ОборотыПродукции.Продукция КАК Продукция,
ОборотыПродукции.КоличествоПродукцииОборот КАК КоличествоПродукции
ИЗ
РегистрНакопления.ОборотПродукции.Обороты(,, Авто) КАК ОборотыПродукции
Шаг 2. Создаем второй набор данных. Назовем его НаборДанныхСырье. Здесь мы будем выбирать только данные по списанию материалов, не затрагивая количественные показатели самого выпуска.
ВЫБРАТЬ
ОборотыСырья.Регистратор КАК Регистратор,
ОборотыСырья.Продукция КАК Продукция,
ОборотыСырья.Сырье КАК Сырье,
ОборотыСырья.КоличествоСырьяОборот КАК КоличествоСырья
ИЗ
РегистрНакопления.ОборотПродукции.Обороты(,, Авто) КАК ОборотыСырья
Шаг 3. Связываем наборы данных. Переходим на вкладку «Связи наборов данных» в схеме компоновки данных. Добавляем новую строку связи:
НаборДанныхВыпускНаборДанныхСырьеРегистратор = Регистратор И Продукция = ПродукцияПочему этот способ решает проблему? СКД рассчитывает итоги по ресурсам для каждого набора данных независимо. Поле КоличествоПродукции рассчитывается только по первому набору данных, где нет никакого дублирования строк сырьем. В итоге, даже если сырье выводится в детальных записях, общие итоги по выпуску продукции будут рассчитаны абсолютно верно.
Бывают ситуации, когда переписывать сложный запрос или делить его на наборы данных нецелесообразно или технически затруднительно. В этом случае на помощь приходит продвинутый функционал выражений СКД. Мы можем оставить исходный соединенный запрос, но изменить формулу расчета ресурса на вкладке «Ресурсы».
Вместо простого выражения Сумма(КоличествоПродукции) мы напишем формулу двойного агрегирования, используя встроенную функцию компоновщика ВычислитьВыражениеСГруппировкойМассив.
Пропишем в поле «Выражение» для ресурса КоличествоПродукции следующую конструкцию:
Сумма(ВычислитьВыражениеСГруппировкойМассив("Максимум(КоличествоПродукции)", "Регистратор, Продукция"))
Разберем детально, как работает эта формула:
Регистратор и Продукция.Максимум(КоличествоПродукции). Это мгновенно «схлопывает» все дублирующие строки сырья, оставляя только одну уникальную цифру выпуска.Сумма складывает полученные уникальные максимальные значения. Цифры сходятся идеально на любом уровне группировки!Если структура вашего отчета жестко фиксирована и пользователи не будут менять её на ходу в режиме «1С:Предприятие», можно применить метод разграничения расчета ресурсов. Этот способ требует аккуратности, но он очень эффективен в простых линейных отчетах.
Переходим на вкладку «Ресурсы» и добавляем поле КоличествоПродукции дважды с разными формулами:
Максимум(КоличествоПродукции). В колонке «Рассчитывать по...» выбираем только те детальные группировки, где выпуск гарантированно уникален в разрезе записей (например, по группировкам Регистратор и Продукция).Сумма(КоличествоПродукции). В колонке «Рассчитывать по...» выбираем только вышестоящие уровни иерархии (например, Склад, Организация, Период) или оставляем поле пустым для автоматического расчета общих итогов.Таким образом, на уровне конкретного документа мы берем максимальное (корректное) значение выпуска, а на верхних уровнях система аккуратно складывает эти локальные максимумы, минуя детальные записи сырья.
По умолчанию СКД использует механизм «Автозаполнение». Это значит, что система сама решает, как оптимизировать запрос при наложении отборов и группировок. Именно эта автоматическая оптимизация часто приводит к некорректному поведению при связях таблиц.
Мы можем отключить автозаполнение и настроить роли полей вручную:
Продукция, КоличествоПродукции) в свойствах полей указываем их роли.Регистратор задаем роль «Период» или ключевое поле, чтобы система понимала границы уникальности записей.Этот способ требует глубокого понимания логики работы компоновщика, но он дает разработчику абсолютный контроль над формируемым SQL-запросом к СУБД.
Мы рассмотрели четыре профессиональных подхода к решению проблемы задвоения данных в СКД. Какой из них выбрать в реальной практике?
ВычислитьВыражениеСГруппировкойМассив в ресурсах). Это быстрое, современное и очень элегантное решение.Успешной вам разработки и только верных итогов в ваших отчетах!