1с получить дерево в запросе
Эту статью я хочу написать в виде конкретных примеров по работе с деревом значений в 1С 8.3 и 8.2.
Дерево значений представляет из себя некую структуру с иерархией. У каждой строки дерева значений может быть сколько угодно подчиненных строк.
Предлагаю сразу начать с примера и получить все записи из справочника «Номенклатура» в виде дерева значений.
Создание дерева значений в 1С
Проще всего это сделать с помощью запроса. Предлагаю создать внешнюю обработку 1С на управляемых формах, добавить на форму табличное поле и кнопку «Получить дерево». По действию кнопки (точнее, команды) выполним простейший запрос.
Вот пример процедуры:
Здесь стоит особенно обратить внимание на два фактора, без которых дерево не сформируется:
- строка в запросе «ИТОГИ ПО Родитель»
- и Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
Если не указать правильно вид обхода результата выборки по запросу, то мы получим обычную таблицу значений.
Результат вывода данного запроса 1С дерево значений на управляемую форму выглядит следующим образом:
Если вы только начинаете программировать в 1С или просто хотите систематизировать свои знания - попробуйте Школу программирования 1С нашего друга Владимира Милькина. Пошаговые и понятные уроки даже для новичка с поддержкой учителя.
Попробуйте бесплатно по ссылке >>
Мы получаем структуру с подчиненными строками. Колонка «Родитель» – это группа, колонка «Номенклатура – это элемент справочника.
Теперь, на мой взгляд, самое интересное. Как организовать обход дерева значений, если мы заранее не знаем, сколько уровней в нем.
Обход дерева значений с помощью рекурсии
В основном обход дерева в 1С делается с помощью рекурсии. Даже когда известно, сколько уровней в нем. С рекурсией это проще, всего около шести строк:
Пример данной обработки для управляемых форм можно скачать по ссылке. С помощью аналогичного кода 1С возможно преобразовать дерево значений в таблицу значений.
При обходе дерева Вы можете выполнять различные действия над ним. Например:
- подсчет итогов по группам;
- раскраску строк по нужным параметрам;
- удалять ненужные строки;
- можно делать различные отборы;
- и так далее.
Работать с деревом значений не так уж и трудно. Фактически это та же таблица значений, но здесь присутствует невидимая колонка «Родитель». Поэтому нет никаких проблем с преобразованием дерева значений в таблицу значений.
Если Вы начинаете изучать 1С программирование, рекомендуем наш бесплатный курс (не забудьте подписаться на YouTube — регулярно выходят новые видео):
Здравствуйте!
Суть вопроса такова: есть РС "Подчинение" (периодический) с измерениями "Оборудование" (Спр. Оборудование) и "Родитель" (Спр. Оборудование). Таким образом хранится история перемещения оборудования с иерархией друг к другу.
Период | Оборудование | Родитель
06.08.2014 | Оборудование_1 |
06.08.2014 | Оборудование_2 |
06.08.2014 | Оборудование_3 |
06.08.2014 | Оборудование_4 |
06.08.2014 | Оборудование_5 |
06.08.2014 | Оборудование_6 |
07.08.2014 | Оборудование_2 | Оборудование_1
07.08.2014 | Оборудование_5 | Оборудование_4
07.08.2014 | Оборудование_6 | Оборудование_5
08.08.2014 | Оборудование_6 |
09.08.2014 | Оборудование_5 | Оборудование_6
09.08.2014 | Оборудование_4 | Оборудование_5
09.08.2014 | Оборудование_2 | Оборудование_3
09.08.2014 | Оборудование_1 | Оборудование_2
Т.е. на 10.08.2014 будет такая картина:
Оборудование_3
__Оборудование_2
____Оборудование_1
Оборудование_6
__Оборудование_5
____Оборудование_4
Вопрос 1 : Как запросом (не в СКД!) получить такое дерево.
Вопрос 2 : Как отловить зацикливание, если попытаться добавить еще одну запись
09.08.2014 | Оборудование_6 | Оборудование_4
(4) PetroP, чтобы не описывать как построена иерархия, прикрепил выгрузку конфигурации. А нужно это для того, чтобы видеть распределение оборудования в определенный момент времени. В данном случае: как было распределено оборудование на 07.08, как на 08.08 и т.д.
(5) MCitrus, уточняющие вопросы:
1) а максимальное число уровней в иерархии известно? или чем либо ограничено?
2) если дерево нужно построить запросом, то нужно буквально дерево значений получить на выходе из запроса, либо плоскую таблицу, имеющую вид дерева. Дело в том, что дерево значений на выходе запроса можно получить только через выражение "итоги по", а там нужно будет точно назвать уровни, по которым будет делаться группировка.
В любом случае посмотрите статьи: Заметочки про 1С:Предприятие 8 (редакция 22.06.2012) - как построить дерево запросом и Уровни, глубина, прародители, циклы и аналоги запросом - как найти зацикленность запросом (Пример 4). Если про зацикленность покажется слишком сложным, могу адаптировать функцию к вашему случаю - там достаточно переписать "пролог". Но тогда уточните, что хотите видеть на выходе: текст запроса или готовую таблицу с "подозрительными" дугами или просто Да/Нет зацикленности.
(6) ildarovich, максимальное число уровней заранее неизвестно. Изначально было 2, но, как показала практика, может дойти и до 6. Статьи прочитал, спасибо огромное. Если сам "пролог" не осилю, тогда обращусь за помощью))
(2) MCitrus,
запросом рекурсию не получишь.
Запросом, можно вытащить фиксированное количество таблиц, и соединить их по нужным критериям.
Типа, в одной выборке берешь остатки на 10, во второй на 9, в третъей на 8.
И соединяешь таблицы по родителю.
Соответственно и зацикливания в запросе быть не может, т.к заранее все известно.
А так, чтобы одна таблица порождала другую, это можно сделать лишь написав рекурсивную функцию.
Сдается мне, что реквизит "Родитель" нужно сделать ресурсом. Измерением оставить только "Оборудование". Как-то это будет логичнее и правильнее. Два родителя ведь быть не может (одновременно, учитывая периодичность). Тогда запрос сводится к получению среза последних. Дерево же строить уже в коде, как написал (3) Boneman, зачем вам сложности с хитрыми запросами?
(7) omut, про ресурс вы четко подметили. Спасибо. Дело в том что дерево нужно построить именно запросом (не в коде). Вот тут-то я застопорился..
(9) MCitrus, Одним запросом дерево не построить, но выпопление этого запроса ножно сделать несколько раз пока не будет выпоплено некое условие, например больше ни чего не найдено.
Была бы база перед глазами я бы вам точно расписал что да как.
(9) MCitrus, если не трудно, скажите, пожалуйста, почему именно запросом и никак иначе. Выше уже коллеги неоднократно и правильно заметили, что запрос - он о другом. Он таблицы формирует. Дерево же только через рекурсию или - в крайнем случае - когда уровень вложенности заранее известен. Увы, каждому свое и дереву не запрос :)
(11) omut, :-))) это я знаю)) Такой вопрос неоднократно поднимался в дебрях инета, ответа на него мне найти не удалось. Я поднял тему в надежде, что кто-то уже победил эту "хотелку" и может поделиться опытом.
Значит строить деревья буду по советам коллег))
(12) MCitrus, вот еще какое соображение пришло в голову.
Требование сделать обработку данных запросом обычно объясняется желанием решить задачу средствами СУБД.
Но СУБД не выдает результат в виде дерева. В T-SQL (в который транслируется запрос) в операторе select нет выражения похожего на "итоги по". Выражение "итоги по" реализуется не в СУБД, а в 1С уже после получения таблицы из СУБД. То есть "итоги по" кажутся внесенными в язык запросов "зародышами" построителя отчета и далее СКД. А значит, не должно быть предубеждения против использования для построения дерева внешних по отношению к запросу средств - это те же "итоги по".
Если все же упереться (почти невозможное всегда интересно), то пока приходит в голову единственное решение:
В информационной базе должен иметься иерархический справочник с разветвленной структурой, который может включить все возможные варианты переподчинения оборудования.
Обычно самой разветвленной структурой обладает справочник номенклатура, но можно завести специальный справочник-скелет "пространство для иерархий". Затем одним запросом определить положение оборудование в узлах иерархии (это можно сделать). Каждому элементу будет соответствовать полный путь от корня типа 1/1/2/1/3/1 или 1/2/3/1, где между разделителями - номера узлов в рамках одного подчинения. По этому пути связать оборудование с элементами справочника "пространство для иерархий". И использовать "итоги по" узлам этого "скелета".
Если ограничить число уровней каким-либо разумным числом, а также ограничить число единиц оборудования в рамках одного подчинения, то справочник-"скелет" легко генерируется.
Не знаю, насколько этот совет применим именно к вашему случаю. Записал его здесь, чтобы не держать в голове эту задачу.
(13) ildarovich, тоже сразу подумал о иерархической структуре. Она решит задачу, если отказаться от истории (регистр ведь периодический, значит история подчинения важна была). А в таком разе задача решится только для текущего состояния (аналог срез последнего), но для просмотра предыдущих состояний все равно придется дерево вручную строить. Ну, как вариант, хранить деревья на каждый момент времени (при каждом изменении подчиненности запоминать, а потом разворачивать). Но это опять объектный метод подразумевает, запросом тут не отделаться :)
Рассматривается применимость и недостатки следующих способов получения дерева
1) Запрос с использованием итогов по иерархии
2) Формирование дерева обходом выборки с упорядочиванием по иерархии
3) Формирование иерархии по списку элементов транзитивным замыканием
1) Идея проста - выбираем запросом элементы, не являющиеся папками, а всю иерархию нам построит запрос. Тут сразу начинаются неожиданности. Какую конструкцию использовать: ИЕРАРХИЯ или ТОЛЬКО ИЕРАРХИЯ? Вроде логично было бы ТОЛЬКО ИЕРАРХИЯ, т.к. итоги на уровне элементов нам не нужны (будут дубли). Заглядываем в справку: "ИЕРАРХИЯ. В результате будут рассчитаны итоги по контрольным точкам и итоги по иерархии для контрольных точек . При необходимости можно рассчитать итоги только значений по иерархии, без расчета итогов в контрольных точках. Для этого перед ключевым словом ИЕРАРХИЯ нужно указать ключевое слово ТОЛЬКО."
Для однозначного понимания моих объяснений введу несколько "терминов", которыми буду пользоваться. Все листья дерева буду называть элементами. Узлы дерева, которые содержат только элементы - нижние папки, Остальные узлы, которые содержат хотя бы одну нижнюю папку - верхние папки.
Для ИЕРАРХИЯ - все логично: разбираем дерево итогов по иерархии для папок. У всех папок тип - ТипЗаписиЗапроса.ИтогПоИерархии. У элементов тип - ТипЗаписиЗапроса.ИтогПоГруппировке. Внутри группировки одна запись того же элемента но уже с типом ТипЗаписиЗапроса.ДетальнаяЗапись. Все как заявлено. Но если выгрузить в дерево, дубль пропадает!
Либо сформировать вручную
Для ТОЛЬКО ИЕРАРХИЯ все немного не так, как ожидалось. Верхние папки - ТипЗаписиЗапроса.ИтогПоИерархии, нижние - ТипЗаписиЗапроса.ИтогПоГруппировке. Внутри элементы с типом - ТипЗаписиЗапроса.ДетальнаяЗапись. НО, если верхняя папка содержит элементы, все они будут помещены в еще в одну вложенную группу с типом ТипЗаписиЗапроса.ИтогПоГруппировке. Поэтому выгрузить() приводит к дублированию! Цель такого дублирования думаю в том, чтобы все элементы обязательно содержались в папке с ТипЗаписиЗапроса.ИтогПоГруппировке, чтобы мы могли обходить выборку ОбходРезультатаЗапроса.ПоГруппировкам. Поэтому, если использовать ТОЛЬКО ИЕРАРХИЯ, лучше обойти выборку и сформировать ручками дерево, устраняя дублирование. При обходе нужно обязательно указывать второй параметр "Группировки". Привожу обход для ТОЛЬКО ИЕРАРХИЯ
Недостатки такого метода очевидны. Все папки вычисляет запрос, и мы не можем как-то их использовать. Например, при соединении с другой таблицей по номенклатуре, склеются только элементы, а на уровне папок нам доступны только вычисления в итогах. Проблема производительности здесь не рассматривается.
2) Для решения этой проблемы необходимо выбрать папки в запросе. Такой запрос не получиться выгрузить в дерево, но, если мы будем использовать в запросе УПОРЯДОЧИТЬ ПО . ИЕРАРХИЯ, а также выберем в запросе родителя, то обход дерева станет простым, мы будем обходить выборку в цикле и прицеплять следующий элемент к текущему или одному из его родителей. К кому цеплять покажет выбранное поле родитель.
Рассмотрим задачу получения только иерархии по набору элементов. Для решения задачи выберем для элементов все папки, в которых они содержатся, затем замыканием вычислим всех родителей этих папок, ну и далее выборка с обходом по 2 методу.
17 правил для составления оптимального ЗАПРОСа к данным базы 1С 44
Для формирования и выполнения запросов к таблицам базы данных в платформе 1С используется специальный объект языка программирования Запрос . Создается этот объект вызовом конструкции Новый Запрос . Запрос удобно использовать, когда требуется получ 1C и Google Maps 21
была поставлена задача отображения на географической карте медицинских учреждений. После обзора предлагаемых решений был выбран сервис google. Но так же подобного рода подход будет работать и с картами сервиса yandex. Во время решения задачи было реш 1С 7.x : Как получить курсы валют с сайта НБУ http://www.bank.gov.ua/ за любую дату ? 6
Функция ПолучитьТаблицуКурсовНБУ(ДатаКурса, Ежедневно = 1) // если в качестве второго параметра указать число отличное от 1 - получем валюты, которые котируются на ежемесячной основе Перем Reader, Url, Точки, HtmlTab, Строк, Р, НомСтроки, НомЯче COM-подключение к базе 7.7 из 8.2 1С 6
Если код выполняется на стороне клиента, то необходимо наличие базы 7.7 на локальной машине. Пример (На форме объекта присутствует реквизит Таблица(ТаблицаЗначений)): НаКлиенте Процедура Загрузки() ПутьКБазе=" D: ВашаБаза 1с77 " ; Пользователь= Cодержимое указанного ниже веб-сайта в этом приложении блокируется. Aboutsecurity_1cv8c.exe 1
Проблема: После обновления на 1С:Бухгалтерию предприятия 3-й версии, при нажатии на закладку командного интерфейса 1С:предприятие, выскакивает ошибка: Aboutsecurity_1cv8c.exe или Aboutsecurity_1cv8.exe «Содержимое указанного ниже веб-узла в э Посмотреть все результаты поиска похожих
Еще в этой же категории
Значения NULL ( ЕСТЬ NULL и ЕСТЬNULL()) 48
NULL – отсутствующие значения. Не путать с нулевым значением! NULL – это не число, не равно пробелу, пустой ссылке, Неопределено. NULL – типообразующее значение, т.е. есть тип NULL и единственное значение этого типа. NULL значения появляются в 17 правил для составления оптимального ЗАПРОСа к данным базы 1С 44
Для формирования и выполнения запросов к таблицам базы данных в платформе 1С используется специальный объект языка программирования Запрос . Создается этот объект вызовом конструкции Новый Запрос . Запрос удобно использовать, когда требуется получ Нарастающий итог в запросе 23
Необходимо использовать левое соединение таблицы с самой собой. ВЫБРАТЬ Обороты.Период, Обороты.Номенклатура, Обороты.Количество ПОМЕСТИТЬ ВТдвижения ИЗ РегистрНакопления.Обороты КАК Обороты ; //////////////////////////////////////////////// Полезные сведения о языке запросов 1С 8.х 22
В статье приведены полезные приемы при работе с запросами 1С v.8.2, а также сведения, которые не так хорошо известны о языке запросов. Я не стремлюсь дать полное описание языка запросов, а хочу остановиться лишь на некоторых моментах, которые для ко Оператор ПОДОБНО 19
ПОДОБНО - Оператор проверки строки на подобие шаблону. Аналог LIKE в SQL. Оператор ПОДОБНО позволяет сравнить значение выражения, указанного слева от него, со строкой шаблона, указанной справа. Значение выражения должно иметь тип строка. Если з Посмотреть все в категории Запросы
17 правил для составления оптимального ЗАПРОСа к данным базы 1С 44
Для формирования и выполнения запросов к таблицам базы данных в платформе 1С используется специальный объект языка программирования Запрос . Создается этот объект вызовом конструкции Новый Запрос . Запрос удобно использовать, когда требуется получ 1C и Google Maps 21
была поставлена задача отображения на географической карте медицинских учреждений. После обзора предлагаемых решений был выбран сервис google. Но так же подобного рода подход будет работать и с картами сервиса yandex. Во время решения задачи было реш 1С 7.x : Как получить курсы валют с сайта НБУ http://www.bank.gov.ua/ за любую дату ? 6
Функция ПолучитьТаблицуКурсовНБУ(ДатаКурса, Ежедневно = 1) // если в качестве второго параметра указать число отличное от 1 - получем валюты, которые котируются на ежемесячной основе Перем Reader, Url, Точки, HtmlTab, Строк, Р, НомСтроки, НомЯче COM-подключение к базе 7.7 из 8.2 1С 6
Если код выполняется на стороне клиента, то необходимо наличие базы 7.7 на локальной машине. Пример (На форме объекта присутствует реквизит Таблица(ТаблицаЗначений)): НаКлиенте Процедура Загрузки() ПутьКБазе=" D: ВашаБаза 1с77 " ; Пользователь= Cодержимое указанного ниже веб-сайта в этом приложении блокируется. Aboutsecurity_1cv8c.exe 1
Проблема: После обновления на 1С:Бухгалтерию предприятия 3-й версии, при нажатии на закладку командного интерфейса 1С:предприятие, выскакивает ошибка: Aboutsecurity_1cv8c.exe или Aboutsecurity_1cv8.exe «Содержимое указанного ниже веб-узла в э Посмотреть все результаты поиска похожих
Еще в этой же категории
Примеры работы с Деревом значений в УП 10
Так как работа с ДеревомЗначений и ТаблицейЗначений в данном контексте практически не отличается, в примере будет использоваться ДеревоЗначений, все тоже самое за исключением иерархии применимо и к ТаблицеЗначений. Как известно, в платформе 1С 8.1 н Дерево значений в таблицу значений или в табличную часть и обратно 9
Для одной организации надо было реализовать документы, где вместо табличной части надо использовать дерево и все это на управляемых формах. Но дерево нельзя сохранить в базе в текущем виде. Пришлось использовать табличную часть документа для хранени Преобразование дерева значений в таблицу значений и обратно 6
Хочу поделиться с посетителями сайта своим подходом к преобразованию таблицы значений в дерево значений и обратно. Вообще, при разработке отраслевой задачи, была необходимость почти во всех документах, выводить информацию в виде дерева и хранить ее Как в дереве значений строку перекинуть в другой родитель? 4
Процедура ПереместитьСтрокуДерева(Дерево, ПеремещаемаяСтрока, НовыйРодитель, Уровень = 0) Если Уровень = 0 Тогда НоваяСтрока = НовыйРодитель.Строки.Добавить(); ЗаполнитьЗначенияСвойств(НоваяСтрока, ПеремещаемаяСтрока); ПереместитьСтрокуДерева(Де Как Свернуть, Развернуть узлы Дерева значений на форме? 3
Как программно свернуть/развернуть дерево значений на управляемой форме? Желательно НаКлиенте. КоллекцияЭлементовДерева=ДеревоНоменклатуры.ПолучитьЭлементы(); //Свернуть дерево Для Каждого Строка Из КоллекцияЭлементовДерева Цикл ИдентификаторСт Посмотреть все в категории Работа с Деревом Значений
Читайте также: