Ещё раз о суммировании группировок в СКД

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

Начнем с дисклеймера.

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

Для начинающего программиста создание отчетов на СКД зачастую является делом не тривиальным. И не только потому, что изучение СКД не входит в общий курс обучения программированию 1с, но и потому, что являясь достаточно разветвленной и самостоятельной подсистемой конфигуратора, имеет свои особенности. Многие рекомендуют изучать книгу Хрусталевой "Разработка сложных отчетов в 1с Предприятии. Система компоновки данных". Именно эта книга, и даже не вся, а только её начало, натолкнуло меня на путь решения задачи, которую до этого я безуспешно пытался решить  в течении 2-х дней. Дело в понимании механизмов работы СКД.

Задача.

Итак, необходимо собрать отчет по использованным на проекты материалам за некий период времени. Сам материал задается подобием, а используемые для этого данные представляют из себя выборку из документов заказа материала со склада производством и требований-накладных, т.е. фактического его списания. Иерархия отчета такова: проект — документ заказа — требования-накладные. Т.е. в проекте может быть много заявок и по каждой заявке может быть несколько списаний одного и того же материала, т.к. забирали заказанные материалы не все сразу, а по частям.

Первоначально подход был такой:
1. Написать запрос в котором соединить заявки и списания по этим заявкам и получать данные для СКД
2. Создать иерархию результатов отчета
3. Механизмами СКД вычислить ресурсы (итоги) по количеству заказанного и фактически списанного для каждой ступени иерархии
4. …и вуаля

План выглядит годным, приступаем к реализации и на выходе получаем такую таблицу:

Обратите внимание, что общее количество заказанного и списанного по заявке не совпадает:

В общем случае так может быть, для этого отчет и делается, но не в этот раз. Также обратите внимание на то, что не совпадает запрошенное количество по конкретной заявке:

Путем нехитрых размышлений приходим к выводу, что 2400 — это ни что иное, как 600*4, т.е. запрошенное по заявке количество * количество списаний по этой завке.

Убеждаемся в этом находя заявку, где количество списаний одно:

Да, для одного списания всё рассчитывается верно. Ошибка найдена: т.к заявка является группировкой, то для неё также рассчитывается ресурс "Количество по заявке". Становится понятно, что дело в том, что после отработки запрос фактически возвращает таблицу вида:

Таблица 1. Исходный запрос

Проект Материал Заказ Списание Кол-во заказ Кол-во списание
141218АСС Брус ДокументЗаказа ДокументСписания№1 600 108
141218АСС Брус ДокументЗаказа ДокументСписания№2 600 18
141218АСС Брус ДокументЗаказа ДокументСписания№3 600 72
141218АСС Брус ДокументЗаказа ДокументСписания№4 600 402

Так как "ДокументЗаказа" — один и тот же, то при вычисление ресурса для группировки по этому документу СКД просуммировал значение поля "Кол-во заказ" 4 раза.

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

Решение.

Как обычно постое, реализуемое за 10 минут с перекурами, если точно (не примерно, а точно) знать что и как работает.
Как я писал в начале, система компоновки данных сложная и развита система внутри платформы. Это целый отдельный механизм. Одной из функциональных особенностей этой системы является механизм связей наборов данных:

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

Таким образом можно вместо одного сложного (а вполне возможно — и очень сложного) исходного запроса написать два простых, разделив тем самым приведенную выше таблицу на две. Таблицу с документами заказа:

Таблица 2. Документы заказа

Проект Материал Документ заказа Кол-во заказ  
141218АСС Брус ДокументЗаказа 600  

и таблицу с документами списаний :

Таблица 3. Документы списаний

Номенклатура Документ списания Кол-во списание Документ-Основание
Брус ДокументСписания№1 108 ДокументЗаказа
Брус ДокументСписания№2 18 ДокументЗаказа
Брус ДокументСписания№3 72 ДокументЗаказа
Брус ДокументСписания№4 402 ДокументЗаказа

где "Документ-Основание" — реквизит документа списания хранящий ссылку на документ заказа материала, по которому это списание проводится.

Для соединения этих запросов в одно целое необходимо выполнить ещё один запрос. Этот последний запрос выполняет за нас механизм "Связи наборов данных", виртуально сделав левое соединение и фактически получив Таблицу 1. Для этого необходимо указать запросы и связываемые поля. В нашем случае это поля "СсылкаНаЗаявку" и "ДокументОснование" в которых хранится ссылка на документ заказа, а также, — т.к. в документах заказа и списания материалов может быть несколько, — поле с материалом:

Ну и указать ресурсы:

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

Что и требовалось доказать.

17 Comments

  1. lunjio

    А чем функции ВычислитьВыражение и ВычислитьВыражениСГруппировкойМассив на худой конец не устраивают ? Пример если честно простоват, если вы пытались обосновать два набора данных и соединение между ними, этот пример не самый лучший вариант.

    Reply
  2. w.r.

    Плохо, что не представлен исходный запрос. Можно было бы подумать над более оптимальным решением, чем связь 2х наборов в СКД

    Reply
  3. w.r.

    (1) ну или так тоже можно

    Reply
  4. Dioneo

    (2) Обычное левое соединение документов списания и документов заказа по полям докзаказа.ссылка=доксписания.док-основание и докзаказа.номенклатура=доксписания.номенклатура

    Reply
  5. Dioneo

    (1) ВычислитьВыражениСГруппировкойМассив пробовал, ожидаемого результата не получил. Наверное не так пробовал…

    Reply
  6. lunjio

    (5) Правильно использовать так — Сумма(ВычислитьВыражениеСГруппировкойМассив(«Максимум(ВашРесурс)», «ВашеПолеЗаявки»)), во втором же поле достаточно обойтись классической суммой. Попробуйте ) Достаточно мощная функция, позволяет много чего сделать, без извращений в запросе.

    Reply
  7. Dioneo

    (6) Премного благодарен!

    Reply
  8. echo77

    (0) Я бы назвал публикацию «Особенности расчета ресурсов при соединении наборов данных в СКД». По сути вы это и показываете — соединив два набора данных в СКД вы получаете правильно рассчитанные итоги.

    В курсе Гилева по СКД, это кстати, было, но не многие(я в том числе не увидел :-)) с первого раза на это обращают внимание.

    Reply
  9. w.r.

    (4) ох уж эти левые соединения, которые плодят дубли, когда в правой таблице строк больше, чем в левой (

    Полагаю, что если бы в запросе СКД дополнительно сгруппировали по полям:

    — Тип заявки

    — Проект

    — Ссылка на заявку

    — Ссылка на ТН

    — Максимум(Количество по заявке)

    — Сумма(Количество по ТН)

    То результат был бы верный

    Но это уже на понимание, как работают запросы, а не особенности СКД

    Reply
  10. AlX0id

    (9)

    А если меняется структура отчета — нужны другие поля, например — вы тоже запрос будете переписывать под каждую из них?

    Reply
  11. w.r.

    (10) в любом случае нужно менять отчёт

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

    Reply
  12. AlX0id

    (11)

    Нет, как раз в случае решения на СКД — не придется менять отчет и у пользователя будет возможность менять структуру.

    То, что программисту проще настроить один вариант отчета и заточить под него запрос — это односзначно. Но это прошлый век.

    Reply
  13. MishaD

    Раз уж в теме собрались знатоки СКД есть вопрос. Как можно сократить выражение:

    Сумма(ВычислитьВыражениеСГруппировкойМассив(«Выбор Когда Сумма(СуммаОтгрузкаТекПериод) > 0 Тогда 1 Иначе 0 Конец», «Контрагент»))

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

    Формат((Сумма(ВычислитьВыражениеСГруппировкойМассив(«Выбор Когда Сумма(СуммаОтгрузкаТекПериод) > 0 Тогда 1 Иначе 0 Конец», «Контрагент»)) —
    Сумма(ВычислитьВыражениеСГруппировкойМассив(«Выбор Когда Сумма(СуммаОтгрузкаПредГод) > 0 Тогда 1 Иначе 0 Конец», «Контрагент»)))/Сумма(ВычислитьВыражениеСГруппировкойМассив(«Выбор Когда Сумма(СуммаОтгрузкаТекПериод) > 0 Тогда 1 Иначе 0 Конец», «Контрагент»)), «ЧДЦ = 2») + «%»

    И это я еще деление на 0 не учитываю. Видимо буду от него избавляться условным оформлением.

    Reply
  14. w.r.

    (12)

    Я не предлагаю отказаться от группировок в СКД, я предлагаю предварительно подготовить данные самым очевидным способом — в запросе

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

    Reply
  15. w.r.

    (13)

    Последняя запись неверна в принципе — если Сумма(СуммаОтгрузкаТекПериод) <= 0, то будет деление на 0

    Reply
  16. MishaD

    (15) Я написал, что буду избавляться условным оформлением. Для других, более коротких конструкций идет выражение через

    Выбор Когда Б <> 0 Тогда Формат((А-Б)/Б, «ЧДЦ = 2″)+»%»
    Когда А > 0 Тогда 100%
    Когда А < 0 Тогда -100%
    Иначе «»
    Конец

    Просто выражение получается очень длинным, если вместо А и Б подставлять подобные выражения.

    Сумма(ВычислитьВыражениеСГруппировкойМассив(«Выбор Когда Сумма(СуммаОтгрузкаТекПериод) > 0 Тогда 1 Иначе 0 Конец», «Контрагент»)
    Reply
  17. par_62

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

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *