Только иерархия 1с как работает скд
Много лазил по форумам, читал вумные книжки, но так и не нашёл для себя решения задачи, описанной ниже. Очень надеюсь, что среди Вас найдутся более знающие и более опытные люди, чем я.
Итак, в базе есть справочник контрагентов с иерархией ЭЛЕМЕНТОВ, есть регистр накопления с показателями продаж этих контрагентов. Задача: вывести контрагентов в иерархическом виде, для каждого контрагента вывести показатель продаж, а также итоговый показатель продаж тех контрагентов, которые находятся "под ним" в структуре справочника НА ВСЕХ НИЖНИХ УРОВНЯХ.
Всю эту кухню надо реализовать на СКД, чтобы иметь возможность строить отчёт с произвольным отбором по реквизитам контрагентов, а также, чтобы можно было менять период продаж.
Например, это выглядеть должно так:
Бьюсь уже пару недель :(
Отдельно иерархию контрагентов получается сделать, показатель продаж достать по конкретному контрагенту нет проблемы. Вся проблема найти сумму по иерархии. Была бы иерархия групп и элементов справочника "Контрагенты", вопросов бы вообще не было.
Вроде, кажется, простой вопрос, а ставит в тупик.
Подбросьте идею, пожалуйста. Спасибо заранее всем откликнувшимся.
(1) Пробовал, но как-то безуспешно. Работало только когда действительно выводил иерархически, но тогда появлялись двойные записи, т.е. под Пупкиным ещё один раз Пупкин был, а мне так не нужно.
(2) В таблице всё верно. 5100 = 3500+500+1000+100
(4) Про такую штуковину думал, но так и не понял, в каком месте её лучше прикрутить. Ведь выводить дерево "без лишних строк" можно двумя способами:
1. Соединять набор с самим собой по полям "Ссылка"-"Родитель" на вкладке "связи наборов данных", но тогда в результат выводятся ДЕТАЛЬНЫЕ записи, где итогов иерархии нет.
2. Выводить иерархично, но определять пользовательское поле с условием отбора, но тогда выводятся не все записи: либо без "листиков", либо вообще лажа какая-то.
(0) Я примерно с подобной задачей бьюсь постоянно. И ниразу ничего адекватного у меня не выходило))) Поэтому буду очень внимательно следить за этой темой. По своим изысканиям: делал и ВЫЧИСЛИТЬВЫРАЖЕНИЕСГРУППИРОВКОЙМАССИВ и вычислитьвыражение, предварительно в запросе как то ставив метку на нужную мне запись, и экспортными функциями как то делал, иногда забиваю на скд и делаю макетом)))) Во общем все мои варианты мне не нравятся самому - поэтому каждый раз нахожусь в поиске нового варианта)
вот вам пример в УПП, иерархия контрагентов построена через реквизит ГоловнойКонтрагент
(0) > справочник контрагентов с иерархией ЭЛЕМЕНТОВ
У вас там МММ что ли?
(10) Не МММ, но задача есть и я её хочу решить. :)
(9) Т.е. если, к примеру, попытаться не использовать стандартную иерархию по родителю, а сделать свою, но тоже по родителю, то будет нужный результат? Фокус-то как раз в иерархии ЭЛЕМЕНТОВ. Завтра попробую замострячить. :)
(9) Кстати, суммы в Вашем скриншоте не так рассчитываются, как мне нужно. Думаю, вряд ли получится. Но попробую.
(15) Уууу. Это да. Напротив Иванова в последней колонке должна быть 1000. Остальное, вроде, нормально. Спасибо за поправочку.
(18) соединить табличку с самой собой по условию, что поле1.Родитель=Поле1 или поле1.родитель.родитель=поле1 .
(22) мне такое не надо, спасибо.
нужно правда учесть, что при большом справочнике такой запрос будет очень долго выполняться
Я простых вопросов не задаю. Это уже крайняя мера для меня - идти на форум и задавать вопрос. Это мой первый вопрос. Обычно, решение нахожу достаточно быстро, но это не тот случай. :(
(24) а справочник очень большой. Может достигать 100000 контрагентов и уровней ой-ёй-ёй сколько.
Рассматривается применимость и недостатки следующих способов получения дерева
1) Запрос с использованием итогов по иерархии
2) Формирование дерева обходом выборки с упорядочиванием по иерархии
3) Формирование иерархии по списку элементов транзитивным замыканием
1) Идея проста - выбираем запросом элементы, не являющиеся папками, а всю иерархию нам построит запрос. Тут сразу начинаются неожиданности. Какую конструкцию использовать: ИЕРАРХИЯ или ТОЛЬКО ИЕРАРХИЯ? Вроде логично было бы ТОЛЬКО ИЕРАРХИЯ, т.к. итоги на уровне элементов нам не нужны (будут дубли). Заглядываем в справку: "ИЕРАРХИЯ. В результате будут рассчитаны итоги по контрольным точкам и итоги по иерархии для контрольных точек . При необходимости можно рассчитать итоги только значений по иерархии, без расчета итогов в контрольных точках. Для этого перед ключевым словом ИЕРАРХИЯ нужно указать ключевое слово ТОЛЬКО."
Для однозначного понимания моих объяснений введу несколько "терминов", которыми буду пользоваться. Все листья дерева буду называть элементами. Узлы дерева, которые содержат только элементы - нижние папки, Остальные узлы, которые содержат хотя бы одну нижнюю папку - верхние папки.
Для ИЕРАРХИЯ - все логично: разбираем дерево итогов по иерархии для папок. У всех папок тип - ТипЗаписиЗапроса.ИтогПоИерархии. У элементов тип - ТипЗаписиЗапроса.ИтогПоГруппировке. Внутри группировки одна запись того же элемента но уже с типом ТипЗаписиЗапроса.ДетальнаяЗапись. Все как заявлено. Но если выгрузить в дерево, дубль пропадает!
Либо сформировать вручную
Для ТОЛЬКО ИЕРАРХИЯ все немного не так, как ожидалось. Верхние папки - ТипЗаписиЗапроса.ИтогПоИерархии, нижние - ТипЗаписиЗапроса.ИтогПоГруппировке. Внутри элементы с типом - ТипЗаписиЗапроса.ДетальнаяЗапись. НО, если верхняя папка содержит элементы, все они будут помещены в еще в одну вложенную группу с типом ТипЗаписиЗапроса.ИтогПоГруппировке. Поэтому выгрузить() приводит к дублированию! Цель такого дублирования думаю в том, чтобы все элементы обязательно содержались в папке с ТипЗаписиЗапроса.ИтогПоГруппировке, чтобы мы могли обходить выборку ОбходРезультатаЗапроса.ПоГруппировкам. Поэтому, если использовать ТОЛЬКО ИЕРАРХИЯ, лучше обойти выборку и сформировать ручками дерево, устраняя дублирование. При обходе нужно обязательно указывать второй параметр "Группировки". Привожу обход для ТОЛЬКО ИЕРАРХИЯ
Недостатки такого метода очевидны. Все папки вычисляет запрос, и мы не можем как-то их использовать. Например, при соединении с другой таблицей по номенклатуре, склеются только элементы, а на уровне папок нам доступны только вычисления в итогах. Проблема производительности здесь не рассматривается.
2) Для решения этой проблемы необходимо выбрать папки в запросе. Такой запрос не получиться выгрузить в дерево, но, если мы будем использовать в запросе УПОРЯДОЧИТЬ ПО . ИЕРАРХИЯ, а также выберем в запросе родителя, то обход дерева станет простым, мы будем обходить выборку в цикле и прицеплять следующий элемент к текущему или одному из его родителей. К кому цеплять покажет выбранное поле родитель.
Рассмотрим задачу получения только иерархии по набору элементов. Для решения задачи выберем для элементов все папки, в которых они содержатся, затем замыканием вычислим всех родителей этих папок, ну и далее выборка с обходом по 2 методу.
Вроде и тема небольшая, не для статьи, но поиски в интернете показали, что найти ответ довольно сложно. Из-за простоты вопроса специалисты обычно отмахиваются, считая, что вопрошающий не разбирается с азами программирования, не понимает рекурсии. В итоге на форумах тема обычно остается без ответа, либо приводится только часть ответа кратко. На самом деле есть «подводные камни», которые нужно знать.
«Подводные камни», мешающие реализовать обход иерархии:
1) В запросе в итогах нужно использовать ключевое слово ИЕРАРХИЯ, например, «ИТОГИ ПО Номенклатура Иерархия»
2) При использовании Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией) ,если есть несколько уровней группировки, нужно указывать второй параметр, строку с именем поля группировки. Например, для иерархической группироки по номенклатуре правильно будет Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией, «Номенклатура»)
3) При обходе выборки мы можем находиться в текущий момент на элементе или папке, для папки необходимо запускать рекурсивно выборку элементов в этой папке. А для элемента нижестоящую выборку, если есть группировки в запросе ниже нашей иерархической группировки, либо ничего не делать, если наша группировка нижняя. Чтобы определить тип элемента, используется функция ТипЗаписи()
Сам алгоритм обхода.
2) Иерархия на первом уровне группировки, второй уровень без иерархии
3) Первый уровень без иерархии, второй с иерархией
4) Первый уровень без иерархии, второй с иерархией (без рекурсии)
Специальные предложения
Рекурсия требует доп.расходов ресурсов и не удобна из-за того, что выходим из области видимости остальных переменных - приходится или параметрами их передавать или объявлять в теле модуля. Любую выборку можно обойти в одной процедуре и без рекурсий.
(1) Согласен. Но в данной статье не рассматривается преобразование рекурсии в циклический алгоритм, т.к. это отдельная тема. Хотя, в принципе, можно добавить нерекурсивный алгоритм в качестве примера.
(8) Я правильно понял, что в примере без рекурсии "ВыбратьДанные" имеется ввиду обработать подчиненные группировки?
Гуд. Но почему нету примера, когда в методе "Выбрать" указывается 3 параметра?
Автор, допиши статью, указав пример с использованием 3-ех параметров (подсказка - хороший пример при работе с датами). Сделай из своей статьи конфетку ;-)
При использовании Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией) обязательно указание второго параметра, строки с именем поля группировки.
Второй параметр вроде как не обязательный. И если у нас нет других полей группировки то можно и не указывать второй параметр.
Спасибо! Решил проблему:)
У меня сейчас есть подобная задача, построить отчет в виде пирамиды сверху вниз, и я вот никак не могу его побороть(((
Уже кажется что в 1С эта задача не реализуема(((
Неоднозначная формулировка, ведь при группировке по иерархии подразумевается, что поле группировки иерархическое. В таком случае действительно будут и папки и элементы. Однако если справочник подчинен элементам? Тогда будут группировки по элементам.
Я бы здесь все-таки разделил. Папки - это те же элементы справочника, как и элементы, которым подчинены другие папки или элементы. А вот когда в запросе выбираются итоги по, то в результат запроса помимо самой выборки платформа добавляет еще группировки (строки итогов).
Сам в очередной раз сталкиваясь с задачей иерархического обхода выборки начинаю по началу вспоминать теорию. Вот следующие выводы, которые мне помогают:
Если в итогах нет модификаторов, то это будут группировки по значению поля. Для иерархического справочника в такой группировке мало смысла, т.к. все элементы уникальны.
Если в итогах указать модификатор ИЕРАРХИЯ, то платформа помимо итоговых группировок для элементов еще добавит элементы иерархии и по ним также итоговые группировки. Получатся итоги по элементам и по группам элементов - избыточное количество итогов. При этом сами элементы иерархии будут входить в свою же группировку.
Если указать модификатор ТОЛЬКО ИЕРАРХИЯ, то платформа добавит итоговые группировки только по элементам иерархии. При этом сами элементы иерархии будут входить в свою же группировку.
И наконец самый практичный вариант: ТОЛЬКО ИЕРАРХИЯ и условие на элемент НЕ ЭтоГруппа. В таком варианте будут выведены элементы сгруппированные по папкам. Однако такой вариант не сработает, если есть иерархия элементов.
Когда происходит обход по иерархической группировке, то этот обход всегда происходит на одном уровне иерархии. Если нам встречается итоговая запись, не важно какой итог (по иерархии или по группе), то нужно выбрать следующий уровень иерархии группировки: для итога по иерархии - ОбходРузультатаЗапроса.ПоГруппировкамСИерархией, а для итога по группировке (всегда присутствует на последнем уровне группировки по выбранному полю) - ПоГруппировкам. При этом нужно обязательно указать имя поля группировки то же самое или просто передать в выборку значение функции Выборка.Группировка(). Это нужно сделать для того, чтобы платформа не выбрала сама следующую группировку итогов или детальные записи, т.к. в платформе такое поведение заложено по-умолчанию.
Рассмотрим, как в СКД вывести ресурс только по нужным уровням иерархии.
Имеем отчет с вот такой структурой:
Структура СКД
У нас есть ресурс «Количество», который вычисляется для всей иерархии:
Задача: необходимо выводить «Количество» только в верхнем уровне иерархии. Сейчас получаемый отчет выглядит так (красным выделены поля, которые должны быть пустыми):
Текущий макет
Что нужно сделать?
Все очень просто, хоть и не совсем очевидно.
Заходим в условное оформление нужной нам группировки и добавляем новое условие:
Новое условное оформление
В поле Оформление ставим флажок напротив «текст» и НИЧЕГО не пишем в текст. Таким образом мы говорим СКД, что надо выводить пустое поле. Выглядеть настройка будет вот так:
Пустой текст в оформлении
В условии используем системное поле «УровеньВГруппировке» и ставим «Не равно» «1». Таким образом мы говорим СКД, что наше оформление распространяется на все уровни группировки, кроме первого (соответственно, если вам надо выводить итоги только для первого и второго уровня, то вид сравнения ставите «Не в списке»,а в значение: «1,2»)
В оформляемых полях выбираем наш ресурс:
Оформляемые поля СКД
Все, больше ничего делать не нужно. Сохраняем наш отчет и проверяем результат:
Результат СКД
Готово! Теперь вы знаете, как в СКД вывести ресурс только по нужным уровням иерархии
Редко какой отчет в 1С не использует отборы, разве что печатные формы и какие-то специальные отчеты. В большинстве отчетов в 1С требуется возможность выборочного анализа. Поэтому в этой статье мы поговорим про настройку отборов в отчетах, построенных с помощью 1С СКД.
После того как вы добавили наборы, определили ресурсы, задали структуру отчета с помощью группировок , можно приступать к настройке фильтров. В СКД это делается на закладке «Отбор», которая доступна или для всего отчета или для определенной группировки.
Новый элемент в список отбора можно добавить несколькими способами – двойной клик по доступному полю, перетаскивание, клавиша в меню:
При этом только через клавишу в меню можно добавить группу в отбор, которая объединяет элементы внутри этой группы по заданному условию (И, ИЛИ).
По умолчанию если элементы отбора не включены ни в какую группу и объединяются с помощью оператора «И».
Вид сравнения в элементе отбора зависит от типа поля (левого значения):
Операции доступные для числа:
Операции доступные для строки:
Для строки добавлены операции – «содержит», «начинается с», «соответствует шаблону» и те же операции с оператором «Не» (Не содержит и т.д.).
Операции доступные для ссылки:
Далее разберем типовые ситуации при использовании отбора
Самый простой вариант использование отбора – добавить фиксированный отбор, который будет действовать всегда (если конечно пользователь не изменит его в варианте отчета):
Обычно такие отборы имеет смысл переносить в текст запроса. Особенно в том случае, если пользователь не должен его менять вообще ни при каком условии.
Иногда в отчете на 1С СКД возникает необходимость исключить в отчете значения некоторых группировок (колонок или строк). Причем сделать это в запросе не представляется возможным, потому что исключать такие строки возможно только после компоновки.
В этом случае используется возможность СКД накладывать отборы на заданную группировку. Рассмотрим, например, такой отчет:
Допустим нам нужно исключить из отчета все строки, в которых итоговое количество по номенклатуре меньше 15. В запросе мы такое условие применить не можем. Установим для этого отбора для группировки «Номенклатура»:
Получим такой отчет:
Отборы на группировках часто используются в отчетах вида «Ведомость по остаткам»:
При использовании группировки по периоду (регистратору) в таких отчетах появляются строки, отвечающие за начальный остаток при использовании даты начала периода отличной от самой ранней. Чтобы убрать такие строки, можно использовать отбор на группировке по регистратору:
Чтобы убрать отбор, выделенный на рисунке на закладке «Другие настройки» для этой же группировки отключим вывод отбора:
Обычно мы редко используем фиксированные отборы. Чаще нам нужны отборы, которые может изменять пользователь. Можно, чтобы пользователь изменял отборы через функционал 1С СКД «Изменить вариант», но это не совсем верный путь – вариант отчета это скорее постоянный «скелет», который настраивается один раз и потом используется многократно. Отборы же это что-то часто изменяемое, поэтому правильнее редактировать их через механизм пользовательских настроек.
Итак, вернемся к нашему отчету. Допустим нам необходимо добавить в отчет отбор по группе номенклатуры (или по элементу) и чтобы этот отбор был доступен для изменения пользователем.
Добавим для этого отбор на уровне отчета. Вид сравнения по умолчанию сделаем «В группе», отключим по умолчанию использование отбора и в диалоге редактирования пользовательских настроек включим наш отбор в пользовательские настройки.
Перейдем теперь в режим предприятия.
Наш отбор доступен для редактирования на форме. За доступность прямо в форме отчета отвечает «Режим редактирования». Значение «Быстрый доступ» означает, что отбор доступен прямо на форме отчета. Если значение равно «Обычный», отбор доступен через кнопку «Настройки». Как видно на рисунке пользователь может выбирать вариант сравнения, управлять действием (включен / отключен) отбора.
Если вам необходимо установить фиксированный отбор (вид сравнения и правое значение константы), но пользователь должен управлять включением / отключением отбора, тогда вам необходимо заполнить представление отбора в пользовательской настройке:
В этом случае в настройки добавляется только флаг использования отбора, которым может управлять пользователь:
Если вам в отборе нужно изменить представления поля, по которому делается отбор, то для этого есть еще одно представление:
Получается вот так:
Мы можем вывести все отборы для редактирования пользователем. Для этого на уровне отчета вызовем диалог редактирования пользовательских настроек:
То же самое можно сделать на уровне любой группировки, если нужно, чтобы была возможность редактирования отборов для заданной группировки. В режиме предприятия это выглядит следующим образом:
Как известно, в 1С СКД используется не только в отчетах, но и в формах, содержащих динамические списки. У динамического списка есть несколько свойств, которые относятся к СКД. Среди этих свойств имеется свойство «Отбор» с типом «ОтборКомпоновкиДанных». Чтобы установить отбор в динамическом списке есть два способа. Первый способ – передать отборы через параметр формы с одноименным названием – «Отбор». Этот параметр является структурой, в которой ключ ссылается на поле, для которого устанавливается отбор. Значение же содержит данные, с которыми производится сравнение. Можно также передать в качестве правого значения – массив, фиксированный массив, список значений. В этом случае вид сравнения равняется «ВСписке», для одиночного элемента вид сравнения устанавливается как «Равно». Этот способ ограничен в возможностях – с его помощью нельзя накладывать сложные условия с операторами «И» и «ИЛИ», нельзя использовать виды сравнения кроме двух указанных.
Отбор, установленный таким образом, передается в фиксированные настройки компоновщика настроек, связанного с динамическим списком. Он не виден пользователю и недоступен для изменения.
Второй способ – непосредственное редактирование отбора в динамическом списке или в компоновщике. Обычно в типовых конфигурация для этого есть ряд методов и функций для установки таких отборов.
Например, вызов основного метода для установки отбора выглядит так:
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбора(Список.Отбор, «Ссылка», Параметры.ДобавитьДля, ВидСравненияКомпоновкиДанных.НеРавно);
Данная функция производит поиск существующего элемента отбора, изменяет его если нашла, а если не нашла, то добавляет с помощью такой процедуры:
В форме содержащей динамический список также как в отчете на СКД, возможно настроить пользовательский отбор. Как это можно сделать показано на рисунке:
Также у элемента формы, с которым связан список нужно установить группу пользовательских настроек, в которой будут отображаться настройки для пользователя:
Читайте также: